Firebird IB ApiGuide
Firebird IB ApiGuide
API Guide
Borland/INPRISE
100 Enterprise Way, Scotts Valley, CA 95066 http://www.interbase.com
Inprise/Borland may have patents and/or pending patent applications covering subject matter in this document.
The furnishing of this document does not convey any license to these patents.
Copyright 1999 Inprise/Borland. All rights reserved. All InterBase products are trademarks or registered
trademarks of Inprise/Borland. All Borland products are trademarks or registered trademarks of Inprise/Borland.
Other brand and product names are trademarks or registered trademarks of their respective holders.
1INT0055WW21001 6E1R0699
Table of Contents
iv INTERBASE 6
Using isc_prepare_transaction2( ) . . . . . . . . . . . . . . . 77
Using isc_rollback_transaction( ) . . . . . . . . . . . . . . . 77
API GUIDE v
How are Blob data stored? . . . . . . . . . . . . . . . . . 119
Blob subtypes. . . . . . . . . . . . . . . . . . . . . . . . . 119
Blob database storage . . . . . . . . . . . . . . . . . . . . 120
Blob data operations . . . . . . . . . . . . . . . . . . . . . . . 120
Reading data from a Blob . . . . . . . . . . . . . . . . . . 121
Writing data to a Blob . . . . . . . . . . . . . . . . . . . . 126
Deleting a Blob . . . . . . . . . . . . . . . . . . . . . . . . 130
Requesting information about an open Blob . . . . . . . . . . 131
Item-list buffer items and result buffer values . . . . . . 131
isc_blob_info( ) call example . . . . . . . . . . . . . . . . 133
Blob descriptors . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Populating a Blob descriptor . . . . . . . . . . . . . . . . . . . 135
Filtering Blob data . . . . . . . . . . . . . . . . . . . . . . . . . 136
Using your own filters . . . . . . . . . . . . . . . . . . . . 136
Declaring an external Blob filter to the database . . . . 137
Writing an external Blob filter . . . . . . . . . . . . . . . 137
Writing an application that requests filtering. . . . . . . 142
vi INTERBASE 6
Using information in the status vector . . . . . . . . . . . . . 172
Checking the status vector for errors . . . . . . . . . . . 173
Displaying InterBase error messages . . . . . . . . . . . 173
Capturing InterBase error messages . . . . . . . . . . . . 174
Setting an SQLCODE value on error . . . . . . . . . . . . 176
Displaying SQL error messages. . . . . . . . . . . . . . . 176
Capturing SQL error messages . . . . . . . . . . . . . . . 177
Parsing the status vector . . . . . . . . . . . . . . . . . . 178
viii INTERBASE 6
isc_array_lookup_desc() . . . . . . . . . . . . . . . . . . . . . . 263
isc_array_put_slice() . . . . . . . . . . . . . . . . . . . . . . . . 266
isc_array_set_desc() . . . . . . . . . . . . . . . . . . . . . . . . 273
isc_attach_database() . . . . . . . . . . . . . . . . . . . . . . . 276
isc_blob_default_desc() . . . . . . . . . . . . . . . . . . . . . . . 279
isc_blob_gen_bpb() . . . . . . . . . . . . . . . . . . . . . . . . . 281
isc_blob_info() . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
isc_blob_lookup_desc() . . . . . . . . . . . . . . . . . . . . . . . 284
isc_blob_set_desc() . . . . . . . . . . . . . . . . . . . . . . . . . 286
isc_cancel_blob() . . . . . . . . . . . . . . . . . . . . . . . . . . 287
isc_cancel_events() . . . . . . . . . . . . . . . . . . . . . . . . . 289
isc_close_blob() . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
isc_commit_retaining() . . . . . . . . . . . . . . . . . . . . . . . 291
isc_commit_transaction() . . . . . . . . . . . . . . . . . . . . . 292
isc_create_blob2() . . . . . . . . . . . . . . . . . . . . . . . . . . 294
isc_create_database( ) . . . . . . . . . . . . . . . . . . . . . . . 297
isc_database_info( ) . . . . . . . . . . . . . . . . . . . . . . . . 297
isc_decode_sql_date() . . . . . . . . . . . . . . . . . . . . . . . . 299
isc_decode_sql_time() . . . . . . . . . . . . . . . . . . . . . . . . 300
isc_decode_timestamp() . . . . . . . . . . . . . . . . . . . . . . 301
isc_delete_user( ) . . . . . . . . . . . . . . . . . . . . . . . . . . 302
isc_detach_database() . . . . . . . . . . . . . . . . . . . . . . . 305
isc_drop_database() . . . . . . . . . . . . . . . . . . . . . . . . 306
isc_dsql_allocate_statement() . . . . . . . . . . . . . . . . . . . 308
isc_dsql_alloc_statement2() . . . . . . . . . . . . . . . . . . . . 310
isc_dsql_describe() . . . . . . . . . . . . . . . . . . . . . . . . . 312
isc_dsql_describe_bind() . . . . . . . . . . . . . . . . . . . . . . 314
isc_dsql_execute() . . . . . . . . . . . . . . . . . . . . . . . . . . 317
isc_dsql_execute2() . . . . . . . . . . . . . . . . . . . . . . . . . 321
isc_dsql_execute_immediate() . . . . . . . . . . . . . . . . . . . 325
isc_dsql_exec_immed2() . . . . . . . . . . . . . . . . . . . . . . 328
isc_dsql_fetch() . . . . . . . . . . . . . . . . . . . . . . . . . . . 330
isc_dsql_free_statement() . . . . . . . . . . . . . . . . . . . . . . 334
API GUIDE ix
isc_dsql_prepare() . . . . . . . . . . . . . . . . . . . . . . . . . . 336
isc_dsql_set_cursor_name() . . . . . . . . . . . . . . . . . . . . 339
isc_dsql_sql_info() . . . . . . . . . . . . . . . . . . . . . . . . . 342
isc_encode_sql_date() . . . . . . . . . . . . . . . . . . . . . . . . 344
isc_encode_sql_time() . . . . . . . . . . . . . . . . . . . . . . . 345
isc_encode_timestamp() . . . . . . . . . . . . . . . . . . . . . . 346
isc_event_block() . . . . . . . . . . . . . . . . . . . . . . . . . . 347
isc_event_counts() . . . . . . . . . . . . . . . . . . . . . . . . . 349
isc_expand_dpb( ) . . . . . . . . . . . . . . . . . . . . . . . . . 351
isc_get_segment( ) . . . . . . . . . . . . . . . . . . . . . . . . . . 353
isc_interprete() . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
isc_modify_user( ) . . . . . . . . . . . . . . . . . . . . . . . . . 356
isc_open_blob2() . . . . . . . . . . . . . . . . . . . . . . . . . . 360
isc_prepare_transaction() . . . . . . . . . . . . . . . . . . . . . 362
isc_prepare_transaction2() . . . . . . . . . . . . . . . . . . . . . 363
isc_print_sqlerror() . . . . . . . . . . . . . . . . . . . . . . . . . 365
isc_print_status() . . . . . . . . . . . . . . . . . . . . . . . . . . 366
isc_put_segment() . . . . . . . . . . . . . . . . . . . . . . . . . . 367
isc_que_events() . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
isc_rollback_retaining( ) . . . . . . . . . . . . . . . . . . . . . . 373
isc_rollback_transaction() . . . . . . . . . . . . . . . . . . . . . 375
isc_service_attach( ) . . . . . . . . . . . . . . . . . . . . . . . . 376
isc_service_detach( ) . . . . . . . . . . . . . . . . . . . . . . . . 377
isc_service_query( ) . . . . . . . . . . . . . . . . . . . . . . . . . 378
isc_service_start( ) . . . . . . . . . . . . . . . . . . . . . . . . . 380
isc_sqlcode( ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
isc_sql_interprete( ) . . . . . . . . . . . . . . . . . . . . . . . . . 382
isc_start_multiple() . . . . . . . . . . . . . . . . . . . . . . . . . 383
isc_start_transaction() . . . . . . . . . . . . . . . . . . . . . . . 386
isc_transaction_info() . . . . . . . . . . . . . . . . . . . . . . . 389
isc_vax_integer() . . . . . . . . . . . . . . . . . . . . . . . . . . 391
isc_version() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
isc_wait_for_event( ) . . . . . . . . . . . . . . . . . . . . . . . . 394
x INTERBASE 6
APPENDIX A InterBase Document Conventions
The InterBase documentation set . . . . . . . . . . . . . . . . 398
Printing conventions . . . . . . . . . . . . . . . . . . . . . . . 399
Syntax conventions . . . . . . . . . . . . . . . . . . . . . . . . 400
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i
API GUIDE xi
xii INTERBASE 6
List of Tables
XIV INTERBASE 6
Table 13.15 Datatypes for array descriptor fields . . . . . . . . . . . . . . . . 264
Table 13.16 Datatypes for array descriptor fields . . . . . . . . . . . . . . . . 274
Table 13.17 Blob descriptor fields . . . . . . . . . . . . . . . . . . . . . . . . 280
Table 13.18 Blob descriptor fields . . . . . . . . . . . . . . . . . . . . . . . . 285
Table 13.19 Error messages for user security functions . . . . . . . . . . . . . 304
Table 13.20 Error messages for user security functions . . . . . . . . . . . . . 358
Table 13.21 Transaction information request item . . . . . . . . . . . . . . . . 389
Table 13.22 Status message return items . . . . . . . . . . . . . . . . . . . . . 390
Table A.1 Books in the InterBase 6 documentation set . . . . . . . . . . . . 398
Table A.2 Text conventions . . . . . . . . . . . . . . . . . . . . . . . . . . 399
Table A.3 Syntax conventions . . . . . . . . . . . . . . . . . . . . . . . . . 400
Table B.1 Array descriptor fields . . . . . . . . . . . . . . . . . . . . . . . . 402
Table B.2 Datatypes for array descriptors . . . . . . . . . . . . . . . . . . . 403
Table B.3 Blob descriptor fields . . . . . . . . . . . . . . . . . . . . . . . . 404
Table B.4 Blob information items and return values . . . . . . . . . . . . . 406
Table B.5 Status message return items . . . . . . . . . . . . . . . . . . . . . 406
Table B.6 Blob parameter buffer parameter types . . . . . . . . . . . . . . . 407
Table B.7 Status message return items . . . . . . . . . . . . . . . . . . . . . 409
Table B.8 Database information items for database characteristics . . . . . . 410
Table B.9 Database information items for environmental characteristics . . . 412
Table B.10 Database information items for performance statistics . . . . . . . 413
Table B.11 Database information items for operation counts . . . . . . . . . 414
Table B.12 DPB parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
Table B.13 Alphabetical list of DPB parameters . . . . . . . . . . . . . . . . 416
Table B.14 SQL datatypes, macro expressions, and C datatypes . . . . . . . . 418
Table B.15 Interpretation of status vector clusters . . . . . . . . . . . . . . . 421
Table B.16 #defines for status vector numeric descriptors . . . . . . . . . . . 422
Table B.17 TPB constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
Table B.18 XSQLDA field descriptions . . . . . . . . . . . . . . . . . . . . . . 427
Table B.19 XSQLVAR field descriptions . . . . . . . . . . . . . . . . . . . . . 428
API GUIDE XV
LIST OF TABLES
XVI INTERBASE 6
CHAPTER
API GUIDE 17
CHAPTER 1 USING THE API GUIDE
Chapter Description
Chapter 2, “Application Requirements” Describes support structures and elements common to
programming with API calls
Chapter 3, “Programming with the InterBase API” Describes special requirements for programming InterBase
applications with the InterBase API
Chapter 4, “Working with Databases” Describes how to attach to and detach from databases, and how to
request information about attachments
Chapter 5, “Working with Transactions” Explains how to start transactions in different modes, and how to
commit them or roll them back
Chapter 6, “Working with Dynamic SQL” Describes how to process DSQL data definition and data
manipulation statements using API calls
Chapter 7, “Working with Blob Data” Describes how to select, insert, update, and delete Blob data in
applications
Chapter 8, “Working with Array Data” Describes how to select, insert, update, and delete array data in
applications
Chapter 9, “Working with Conversions” Describes how to select, insert, update, and delete date and time
data in applications, and how to reverse the byte order of numbers
with isc_vax_integer()
Chapter 10, “Handling Error Conditions” Describes how to trap and handle database errors in applications
Chapter 11, “Working with Events” Explains how triggers interact with applications and describes how
to register interest in events, wait on them, and respond to them in
applications
TABLE 1.1 API Guide chapters
18 INTERBASE 6
SAMPLE DATABASE AND APPLICATIONS
Chapter Description
Chapter 12: “Working with Services”
Chapter 13, “API Function Reference” Describes the syntax of each function call in detail.
Appendix A, “InterBase Document Conventions” Lists typefaces and special characters used in this book to describe
syntax and identify object types.
Appendix B, “Data Structures” Lists and describes the data structures, constants, and buffers that
are defined in ibase.h.
TABLE 1.1 API Guide chapters (continued)
API GUIDE 19
CHAPTER 1 USING THE API GUIDE
20 INTERBASE 6
PART I
API PartI:
User’s
Guide
Part I: API User’s Guide
API GUIDE 21
22 INTERBASE 6
CHAPTER
Application Requirements
Chapter2
2
This chapter summarizes programming requirements for using categories of API
functions in database applications, and provides cross-references to more detailed
information in later chapters.
All API applications must use certain API functions and support structures. For example,
all applications connect to at least one database, and run at least one transaction. All
applications, therefore, must declare and initialize database handles and transaction
handles. They may also need to declare and populate database parameter buffers (DPBs),
transaction parameter buffers (TPBs), and service parameter buffers (SPBs). This chapter
outlines those requirements, and points you to more detailed information later in this
book.
Some API applications may use specific API functions, such as the functions that permit
an application to process dynamic SQL (DSQL) statements. These applications have
additional requirements that are also outlined in this chapter along with pointers to more
detailed information elsewhere in this book.
API GUIDE 23
CHAPTER 2 APPLICATION REQUIREMENTS
Including ibase.h
The InterBase subdirectory, include, contains the ibase.h header file, which should be
included in all source code modules for API applications. ibase.h contains API function
prototypes. It also contains structure typedefs, parameter definitions, and macros
required by various API functions.
To include ibase.h in a source code module, insert the following #include near the start of
the source code:
#include <ibase.h>
If ibase.h is not on your compiler’s search path, you may need to provide a full path
specification and enclose the file name in quotation marks.
Failure to include ibase.h can prevent the successful compilation and linking of an
application.
Database requirements
All applications that work with databases must provide one database handle for each
database to be accessed. A database handle is a long pointer that is used in API functions
to attach to a database and to reference it in subsequent API calls. The InterBase header
file, ibase.h, contains a #define useful for declaring database handles.
When establishing a connection to a database, optional database attachment
characteristics, such as a user name and password combination, can be passed to the
attachment through a database parameter buffer (DPB). Usually, one DPB is set up for
each database attachment, although database attachments can also share a DPB.
24 INTERBASE 6
REQUIREMENTS FOR ALL APPLICATIONS
4 Setting up a DPB
A DPB is a byte array describing optional database attachment characteristics. A DPB
must be set up and populated before attaching to a database. Parameters that can be
passed to the DPB are defined in ibase.h.
For more information about setting up, populating, and using a DPB, see Chapter 4,
“Working with Databases.”
Transaction requirements
All applications must provide one transaction handle for each transaction to be accessed.
A transaction handle is a long pointer that is used in API functions to start a transaction
and to reference it in subsequent API calls. The InterBase header file, ibase.h, contains a
#define useful for declaring transaction handles.
When starting a transaction, optional transaction characteristics, such as access method
and isolation level, can be passed to the start-up call through a transaction parameter
buffer (TPB). Usually, one TPB is set up for each transaction, although transactions with
the same operating characteristics can also share a TPB.
API GUIDE 25
CHAPTER 2 APPLICATION REQUIREMENTS
. . .
/* Initialize the handle. */
tr1 = 0L;
For more information about declaring, initializing, and using transaction handles, see
Chapter 5, “Working with Transactions.”
4 Setting up a TPB
A TPB is a byte array containing parameters that describe optional transaction
characteristics. In these cases, the TPB must be set up and populated before starting a
transaction. Parameters that can be passed to the TPB are defined in ibase.h.
For more information about setting up, populating, and using a TPB, see Chapter 5,
“Working with Transactions.”
Additional requirements
The following sections outline possible additional requirements for API applications
developed on certain system platforms, such as Microsoft Windows, and for general
classes of API functions, such as those that process DSQL statements.
26 INTERBASE 6
ADDITIONAL REQUIREMENTS
When Windows client applications make calls and cast C datatypes, they should make
explicit use of the ISC_FAR declaration.
Note The ISC_EXPORT keyword is omitted from the API function reference because on all
non-Windows platforms it is undefined.
For more information about Windows requirements, see Chapter 3, “Programming
with the InterBase API.”
DSQL requirements
API applications that build or prompt for DSQL queries at run time require careful
declaration, initialization, and population of extended SQL descriptor area ( XSQLDA)
structures for data transfer to and from the database. In addition, many API functions,
such as isc_dsql_allocate_statement() and isc_dsql_describe(), also make use of
statement handles for DSQL processing.
ibase.h provides typedefs for the XSQLDA structure, and its underlying structure, the
XSQLVAR. It also provides a #define for the statement handle, a macro for allocating the
appropriate amount of space for an instance of an XSQLDA in an application, and #defines
for DSQL information parameters passed to isc_dsql_sql_info().
The following code illustrates how to declare an XSQLDA structure for use in an
application, and how to declare a statement handle:
#include <ibase.h>
. . .
XSQLDA *insqlda;
isc_stmt_handle sql_stmt;
. . .
For more information about DSQL programming with the API, see Chapter 6, “Working
with Dynamic SQL.”
Blob requirements
To work with Blob data that must be filtered, an API application must set up a Blob
parameter buffer (BPB) for each Blob. A BPB is a variable-length byte vector declared in
an application to store control information that dictates Blob access. The BPB can contain
a number of constants, defined in ibase.h, that describe the Blob and the Blob subtypes
that specify Blob filtering.
API GUIDE 27
CHAPTER 2 APPLICATION REQUIREMENTS
Applications that work with Blob data in an international environment must also declare
and populate a Blob descriptor that contains character set information for the Blob. The
Blob descriptor structure is defined in ibase.h. To declare a Blob descriptor, an application
must provide code like this:
#include <ibase.h>
. . .
ISC_BLOB_DESC to_desc;
Except on NetWare servers, where they are not supported, Blob filters enable a Blob to
be translated from one format to another, such as from a compressed state to an
decompressed state or vice versa. If Blob filters are desired, separate filter functions must
be created and defined to the database to ensure their use when Blob data is accessed.
Finally, to access Blob data, applications must make extensive use of API DSQL functions.
For more information about working with Blob data and Blob filters, see
Chapter 7, “Working with Blob Data.”For more information about DSQL, see Chapter
6, “Working with Dynamic SQL.”
Array requirements
API functions that handle array processing require the use of an array descriptor structure
and array IDs, defined in ibase.h. In addition, applications accessing arrays must make
extensive use of API DSQL functions.
The following code illustrates how to declare an array descriptor and array ID variable,
and how to initialize an array ID to zero before use:
#include <ibase.h>
. . .
ISC_ARRAY_DESC desc;
ISC_QUAD array_id;
. . .
array_id = 0L;
. . .
For more information about working with arrays, see Chapter 8, “Working with Array
Data.”For more information about DSQL, see Chapter 6, “Working with Dynamic
SQL.”
28 INTERBASE 6
ADDITIONAL REQUIREMENTS
Event requirements
InterBase events are messages passed from a trigger or stored procedure to an application
to announce the occurrence of specified conditions or actions, usually database changes
such as insertions, modifications, or deletions of records.
Before an application can respond to an event, it must register interest in an event. To
register interest in an event, the application must establish and populate two event
parameter buffers (EPBs), one for holding the initial occurrence count values for each
event of interest, and another for holding the changed occurrence count values. These
buffers are passed as parameters to several API event functions, and are used to
determine which events have occurred.
In C, each EPB is declared as a char pointer, as follows:
char *event_buffer, *result_buffer;
Once the buffers are declared, isc_event_block() is called to allocate space for them, and
to populate them with starting values.
For more information about events, see Chapter 11, “Working with Events.”
Error-handling requirements
Most API functions return status information in an error status vector, an array of 20
longs. To handle InterBase error conditions, should they arise, applications should
declare a status vector as follows:
#include <ibase.h>
. . .
ISC_STATUS status_vector[20];
API GUIDE 29
CHAPTER 2 APPLICATION REQUIREMENTS
Services requirements
InterBase provides an API interface to enable your applications to request information
about server and database properties, and to invoke tasks to administer servers and
databases. Your application can initiate a connection to a local instance of the InterBase
server, or to a remote server over a network. Through this connection, your application
submits requests to the server and receives resultant data.
For more information about using this API facility, see Chapter 12, “Working with
Services.”
30 INTERBASE 6
CHAPTER
Programming with
Chapter3
3
the InterBase API
API GUIDE 31
CHAPTER 3 PROGRAMMING WITH THE INTERBASE API
32 INTERBASE 6
SPECIFYING USER NAME AND PASSWORD
The ISC_USER and ISC_PASSWORD environment variables are used together to establish a
valid user name and password combination to pass to the remote InterBase database
server.
API GUIDE 33
CHAPTER 3 PROGRAMMING WITH THE INTERBASE API
IMPORTANT Do not use the ISC_PASSWORD environment variable when security is a concern. Anyone
with access to a client where an ISC_PASSWORD environment variable is defined in a file
such as autoexec.bat can easily view the password.
Datatypes
InterBase supports a wide variety of datatypes for application development. These
datatypes are defined in a typedef to be platform-independent. The InterBase client
libraries are also compiled with packed data structures to be compatible with a variety of
platforms.
For more information about InterBase datatypes, see the Language Reference.
34 INTERBASE 6
CALLING CONVENTIONS
Calling conventions
Conventions for calling functions vary from platform to platform. Specifically:
g On UNIX platforms, use the C calling conventions (cdecl) in all cases.
g On Windows 95 and Windows NT, use the standard calling conventions (_stdcall) for all
functions that have a fixed number of arguments. There are only three functions that have
a variable number of arguments. For these three—isc_start_transaction(),
isc_expand_dpb(), and isc_event_block()—use the cdecl conventions.
Building applications
This section discusses compilers and libraries that are needed to build InterBase
applications.
HELP WITH LINKING AND COMPILING On each platform, there is a makefile in the
examples directory that contains detailed platform-specific information about linking and
compiling. Open the makefile in a text editor to access the information.
Compilers
The import libraries included with InterBase have been tested with the following
compilers:
Windows platforms
g Borland C++ 5.0
g Microsoft Visual C++ 2.0
g Microsoft Visual C++ 4.0
Solaris
gC SPARCWorks SC4.2 C compiler
g C++ SPARCWorks SC3.0.1 C++ compiler
g COBOL MicroFocus Cobol 4.0
g ADA SPARCWorks SC4.0 Ada compiler
g FORTRAN SPARCWorks SC4.0 Fortran compiler
API GUIDE 35
CHAPTER 3 PROGRAMMING WITH THE INTERBASE API
HP-UX
gC HP C/HP-UX Version A.10.32
g C++ HP C++/HP-UX Version A.10.22
g COBOL MicroFocus Cobol 4.0
g ADA Alsys Ada - AdaWorld V5.5.4
g FORTRAN HP Fortran/9000 10.20 Release
Linking
The InterBase library files reside in the lib subdirectory of the installation directory.
Applications must link with the InterBase client library. This library name varies
depending on the platform and the compiler.
Include files
Applications must include the ibase.h header file to pick up the InterBase type definitions
and function prototypes. This file is in the include subdirectory of the InterBase install
directory.
On UNIX platforms, the gds.h file is available in the installation directory for backward
compatibility.
36 INTERBASE 6
BUILDING APPLICATIONS
Option Action
c Compile without linking (DLLs only)
Zi Generate complete debugging information
DWIN32 Defines “WIN32” to be the null string
D_MT Use a multi-thread, statically-linked library
TABLE 3.3 Microsoft C compiler options
For example, these commands use the Microsoft compiler to build a DLL that uses
InterBase:
cl -c -Zi -DWIN32 -D_MT -LD udf.c
lib -out:udf.lib -def:funclib.def -machine:i586 -subsystem:console
link -DLL -out:funclib.dll -DEBUG:full,mapped -DEBUGTYPE:CV
-machine:i586 -entry:_DllMainCRTStartup@12 -subsystem:console
-verbose udf.obj udf.exp gds32.lib ib_util_ms.lib crtdll.lib
Note See “Working with UDFs” in the Developer’s Guide for more about compiling and
linking user-defined libraries.
Using the Dynamic Runtime Library If you are
· using a Microsoft Visual C++ 2.0 or Microsoft Visual C++ 4.0
· compiling and linking separately, and
· using the Dynamic Runtime Library (msvcrt20.dll or msvcrt40.dll)
you need to use the /MD compiler flag to compile with the run time library (RTL), as well
as linking with the correct import library.
API GUIDE 37
CHAPTER 3 PROGRAMMING WITH THE INTERBASE API
Option Action
v Turns on source debugging
a4 Structure padding/byte alignment
DWIN32 • Defines the string “WIN32”
• With no argument, it defines it to the null string
tWM Makes the target multi-threaded
tWC: • Makes the target a console .EXE with all functions exportable
• Cannot be used with the -tWCD option
tWCD Makes the target a console .DLL with all functions exportable; cannot be used
with the -tWC option
TABLE 3.4 Borland C compiler options
The following command creates a DLL named funclib.dll from a source file named udf.c:
implib mygds32.lib \interbas\bin\gds32.dll
bcc32 -v -a4 -DWIN32 -tWM -tWCD -efunclib.dll udf.c mygds32.lib
The following commands create an InterBase executable named udftest.exe (which calls
into funclib.dll) from a source file named udftest.e containing embedded SQL commands.
implib udf.lib funclib.dll
gpre -e udftest.e
bcc32 -v -a4 -DWIN32 -tWM -tWC udftest.c udf.lib mygds32.lib
When linking applications with Borland C command line linker, use the /c option (case
sensitive link).
Note There are equivalent general linker options within the Borland Integrated
Development Environment (IDE). The default in the IDE is case-sensitive link (/c option)
alone, which causes unresolved linker errors for all of the InterBase entry points.
38 INTERBASE 6
BUILDING APPLICATIONS
4 IDE default
The case-sensitive link (/c option) is the default in the IDE.
DIRECTORIES
Include directory: interbase_home_dir\include
Library directory: interbase_home_dir\lib
Note The default InterBase home directory is c:\Program Files\InterBase Corp\InterBase.
COMPILER
Source language compliance: Borland extensions
32-bit Compiler
Data alignment: Byte (-a4 option for 4 byte alignment)
LINKER
Choose Case-sensitive link ON (/c option).
API GUIDE 39
CHAPTER 3 PROGRAMMING WITH THE INTERBASE API
g Because the Borland C++Builder prepends an underscore to some API functions that
gds32.dll exports without the underscore, you may need to add aliases for these functions
to your module definition file, as in the following example:
IMPORTS
_isc_start_transaction = GDS32.isc_start_transaction
Example programs
Example programs demonstrating how to use the InterBase API are included in the
examples subdirectory of the InterBase installation directory. There is also a sample .def
file.
On NT, there are two make files, makefile.bc for the Borland compiler and linker, and
makefile.msc for the Microsoft compiler and linker. In both files, you must modify the IBASE
environment variable to point to an absolute path.
In the .bc make file, modify the BCDIR variable to point to the absolute path to the Borland
compiler and linker.
In the .msc make file, modify the MSCDIR variable to point to the absolute path to the
Microsoft compiler and linker.
To build the example applications on NT using Borland C++, use the following
command:
make -B -f makefile.bc all
To build the example applications using Microsoft C++, use this command:
nmake -B -f makefile.msc all
40 INTERBASE 6
CHAPTER
API GUIDE 41
CHAPTER 4 WORKING WITH DATABASES
The following table lists the API functions for working with databases. The functions are
listed in the order that they typically appear in an application.
Call Purpose
isc_expand_dpb() Specifies additional parameters for database access, such as user names
and passwords elicited from a user at run time; uses a previously declared
and populated DPB
isc_attach_database() Connects to a database and establishes initial parameters for database
access, such as number of cache buffers to use; uses a previously declared
and populated DPB
isc_database_info() Retrieves requested information about an attached database, such as the
version of the on-disk structure (ODS) that it uses
isc_detach_database() Disconnects from an attached database and frees system resources
allocated to that attachment
isc_drop_database() Deletes a database and any support files, such as shadow files
TABLE 4.1 API database functions
Connecting to databases
Connecting to one or more databases is a four-step process:
1. Creating and initializing a database handle for each database to be attached.
2. Creating and populating a DPB for each database to be attached.
3. Optionally calling isc_expand_dpb() prior to actual attachment to add more
database parameters to a previously created and populated DPB.
4. Calling isc_attach_database() for each database to which to connect.
These steps are described in the following sections of this chapter.
42 INTERBASE 6
CONNECTING TO DATABASES
To use this typedef for declaring database handles in an application, include ibase.h in
each source file module:
#include <ibase.h>
Once a database is no longer attached, its handle can be assigned to a different database
in a subsequent attachment. If an application accesses several databases, but only
accesses a subset of databases at the same time, it is only necessary to declare as many
handles as there will be simultaneous database accesses. For example, if an application
accesses a total of three databases, but only attaches to two of them at a time, only two
database handles need be declared.
API GUIDE 43
CHAPTER 4 WORKING WITH DATABASES
Tip Some of the DPB parameters correspond directly to gfix options. In fact, that’s how gfix is
implemented: it sets certain DPB parameters and attaches to a database, where it
performs the requested operation (sweep, set async writes, shutdown, and so on).
A DPB is a char array variable declared in an application, that consists of the following
parts:
1. A byte specifying the version of the parameter buffer, always the
compile-time constant, isc_dpb_version1.
2. A contiguous series of one or more clusters of bytes, each describing a single
parameter.
Each cluster consists of the following parts:
1. A one-byte parameter type. There are compile-time constants defined for all
the parameter types (for example, isc_dpb_num_buffers).
2. A one-byte number specifying the number of bytes that follow in the
remainder of the cluster.
3. A variable number of bytes, whose interpretation (for example, as a number
or as a string of characters) depends on the parameter type.
For example, the following code creates a DPB with a single parameter that sets the
number of cache buffers to use when connecting to a database:
char dpb_buffer[256], *dpb, *p;
short dpb_length;
/* Construct the database parameter buffer. */
dpb = dpb_buffer;
*dpb++ = isc_dpb_version1;
44 INTERBASE 6
CONNECTING TO DATABASES
*dpb++ = isc_num_buffers;
*dpb++ = 1;
*dpb++ = 90;
dpb_length = dpb - dpb_buffer;
IMPORTANT All numbers in the database parameter buffer must be represented in a generic format,
with the least significant byte first, and the most significant byte last. Signed numbers
should have the sign in the last byte. The API function isc_vax_integer() can be used to
reverse the byte order of a number. For more information, see “isc_vax_integer()” on
page 391.
The following table lists DPB items by purpose:
User validation
User name isc_dpb_user_name
Password isc_dpb_password
Encrypted password isc_dpb_password_enc
Role name isc_dpb_sql_role_name
System database administrator’s user name isc_dpb_sys_user_name
Authorization key for a software license isc_dpb_license
Database encryption key isc_dpb_encrypt_key
Environmental control
Number of cache buffers isc_dpb_num_buffers
dbkey context scope isc_dpb_dbkey_scope
System management
Force writes to the database to be done asynchronously or synchronously isc_dpb_force_write
Specify whether or not to reserve a small amount of space on each database isc_dpb_no_reserve
page for holding backup versions of records when modifications are made
System management
Specify whether or not the database should be marked as damaged isc_dpb_damaged
Perform consistency checking of internal structures isc_dpb_verify
TABLE 4.2 DPB parameters
API GUIDE 45
CHAPTER 4 WORKING WITH DATABASES
Shadow control
Activate the database shadow, an optional, duplicate, in-sync copy of the isc_dpb_activate_shadow
database
Delete the database shadow isc_dpb_delete_shadow
Replay logging system control
Activate a replay logging system to keep track of all database calls isc_dpb_begin_log
Deactivate the replay logging system isc_dpb_quit_log
Character set and message file specification
Language-specific message file isc_dpb_lc_messages
Character set to be utilized isc_dpb_lc_ctype
TABLE 4.2 DPB parameters (continued)
The following table lists DPB parameters in alphabetical order. For each parameter, it lists
its purpose, the length, in bytes, of any values passed with the parameter, and the value
to pass.
46 INTERBASE 6
CONNECTING TO DATABASES
API GUIDE 47
CHAPTER 4 WORKING WITH DATABASES
Parameter Purpose
isc_dpb_user_name String user name, up to 255 characters
isc_dpb_password String password, up to 255 characters
isc_dpb_lc_messages String specifying a language-specific message file
isc_dpb_lc_ctype String specifying the character set to be utilized
TABLE 4.4 DPB parameters recognized by isc_expand_dpb()
IMPORTANT If you expect to add any of these parameters at run time, then create a larger than
necessary DPB before calling isc_expand_dpb(), so that this function does not need to
reallocate DPB storage space at run time. isc_expand_dbp() can reallocate space, but
that space is not automatically freed when the database is detached.
isc_expand_dpb() requires the following parameters:
The third parameter in the table, “…”, indicates a variable number of replaceable
parameters, each with different names, but each a character pointer.
The following code demonstrates how isc_expand_dpb() is called to add a user name
and password to the DPB after they are elicited from a user at run time:
char dpb_buffer[256], *dpb, *p;
char uname[256], upass[256];
short dpb_length;
48 INTERBASE 6
CONNECTING TO DATABASES
dpb = dpb_buffer;
*dpb++ = isc_dpb_version1;
*dpb++ = isc_num_buffers;
*dpb++ = 1;
*dpb++ = 90;
dpb_length = dpb - dpb_buffer;
/* Now ask user for name and password. */
prompt_user("Enter your user name: ");
gets(uname);
prompt_user("\nEnter your password: ");
gets(upass);
/* Add user name and password to DPB. */
dpb = dbp_buffer;
isc_expand_dpb(&dpb, &dpb_length,
isc_dpb_user_name, uname,
isc_dpb_password, upass,
NULL);
Attaching to a database
After creating and initializing a database handle, and optionally setting up a DPB to
specify connection parameters, use isc_attach_database() to establish a connection to an
existing database. Besides allocating system resources for the database connection,
isc_attach_database() also associates a specific database with a database handle for use
in subsequent API calls that require a handle.
isc_attach_database() expects six parameters:
g A pointer to an error status array, where attachment errors can be reported should they
occur.
g The length, in bytes, of the database name for the database to open. If the database name
includes a node name and path, these elements must be counted in the length argument.
g A string containing the name of the database to attach. The name can include a node
name and path specification.
g A pointer to a previously declared and initialized database handle with which to associate
the database to attach. All subsequent API calls use the handle to specify access to this
database.
g The length, in bytes, of the DPB. If no DPB is passed, set this value to zero.
g A pointer to the DPB. If no DPB is passed, set this to NULL.
Each database attachment requires a separate call to isc_attach_database().
API GUIDE 49
CHAPTER 4 WORKING WITH DATABASES
The following code illustrates how to attach to a database without passing a DPB:
#include <ibase.h>
. . .
isc_db_handle db1;
char *str = "employee.gdb";
ISC_STATUS status_vector[20];
. . .
/* Set database handle to zero before attaching to a database. */
db1 = 0L;
/* Attach to the database. */
isc_attach_database(status_vector, strlen(str), str, &db1, 0, NULL);
if (status_vector[0] == 1 && status_vector[1])
50 INTERBASE 6
REQUESTING INFORMATION ABOUT AN ATTACHMENT
{
error_exit();
}
. . .
API GUIDE 51
CHAPTER 4 WORKING WITH DATABASES
4 Database characteristics
Several items are available for determining database characteristics, such as its size and
major and minor ODS version numbers. The following table lists the request buffer items
that can be passed, and the information returned in the result buffer for each item type
:
52 INTERBASE 6
REQUESTING INFORMATION ABOUT AN ATTACHMENT
API GUIDE 53
CHAPTER 4 WORKING WITH DATABASES
4 Environmental characteristics
Several items are provided for determining environmental characteristics, such as
the amount of memory currently in use, or the number of database cache buffers
currently allocated. These items are described in the following table:
Note Not all environmental information items are available on all platforms.
4 Performance statistics
There are four items that request performance statistics for a database. These statistics
accumulate for a database from the moment it is first attached by any process until the
last remaining process detaches from the database.
For example, the value returned for isc_info_reads is the number of reads since the
current database was first attached, that is, an aggregate of all reads done by all attached
processes, rather than the number of reads done for the calling program since it attached
to the database.
54 INTERBASE 6
REQUESTING INFORMATION ABOUT AN ATTACHMENT
Tip To determine an actual table name from a table ID, query the system table,
RDB$RELATION.
API GUIDE 55
CHAPTER 4 WORKING WITH DATABASES
The following table describes the items which return count values for operations on the
database:
isc_database_info(
status_vector,
&handle, /* Set in previous isc_attach_database() call. */
56 INTERBASE 6
DISCONNECTING FROM DATABASES
sizeof(db_items),
db_items,
sizeof(res_buffer),
res_buffer);
if (status_vector[0] == 1 && status_vector[1]) {
/* An error occurred. */
isc_print_status(status_vector);
return(1);
};
/* Extract the values returned in the result buffer. */
for (p = res_buffer; *p != isc_info_end ; ) {
item = *p++
length = isc_vax_integer(p, 2);
p += 2;
switch (item){
case isc_info_page_size:
page_size = isc_vax_integer(p, length);
break;
case isc_info_num_buffers:
num_buffers = isc_vax_integer(p, length);
break;
default:
break;
}
p += length;
};
API GUIDE 57
CHAPTER 4 WORKING WITH DATABASES
Deleting a database
To remove a database from the system if it is no longer needed, use isc_drop_database().
This function permanently wipes out a database, erasing its data, metadata, and all of its
supporting files, such as secondary files, shadow files, and write-ahead log files.
A database can only be deleted if it is previously attached with a call to
isc_attach_database(). The call to isc_attach_database() establishes a database handle
for the database. That handle must be passed in the call to isc_drop_database().
For example, the following code deletes the database pointed to by the database handle,
db1:
#include <ibase.h>
. . .
isc_db_handle db1;
char *str = "employee.gdb";
ISC_STATUS status_vector[20];
. . .
/* Set database handle to zero before attaching to a database. */
db1 = 0L;
/* Attach to the database. */
isc_attach_database(status_vector, strlen(str), str, &db1, 0, NULL);
if (status_vector[0] == 1 && status_vector[1])
{
error_exit();
}
isc_drop_database(status_vector, &db1);
if (status_vector[0] == 1 && status_vector[1])
{
error_exit();
}
. . .
58 INTERBASE 6
CHAPTER
Working with
Chapter5
5
Transactions
This chapter describes how to set up a transaction parameter buffer (TPB) that contains
parameters, how to set up and initialize transaction handles, and how to use the API
functions that control transactions. It also explains how to retrieve a transaction ID.
All data definition and data manipulation in an application takes place in the context of
one or more transactions, one or more statements that work together to complete a
specific set of actions that must be treated as an atomic unit of work.
API GUIDE 59
CHAPTER 5 WORKING WITH TRANSACTIONS
The following table summarizes the API functions most commonly used when working
with transactions. Functions are listed in the order they typically appear in an application.
Function Purpose
isc_start_transaction() Starts a new transaction against one or more databases.; use a
previously declared and populated TPB
isc_commit_retaining() Commits a transaction’s changes, and preserves the transaction
context for further transaction processing
isc_commit_transaction() Commits a transaction’s changes, and ends the transaction
isc_rollback_transaction() Rolls back a transaction’s changes, and ends the transaction
TABLE 5.1 API transaction functions
In addition to these functions, the following table lists less frequently used API
transaction functions in the order they typically appear when used:
Function Purpose
isc_start_multiple() Starts a new transaction against one or more databases; used
instead of isc_start_transaction() for programming languages such
as FORTRAN, that do not support variable numbers of arguments to
functions
isc_prepare_transaction() Performs the first phase of a two-phase commit, prior to calling
isc_commit_transaction(); used only when it is absolutely necessary
to override InterBase’s automatic two-phase commit
isc_prepare_transaction2() Performs the first phase of a two-phase commit, prior to calling
isc_commit_transaction(); used only when absolutely necessary to
override InterBase’s automatic two-phase commit
TABLE 5.2 Additional API transaction functions
Starting transactions
Starting transactions is a three-step process:
1. Creating and initializing a transaction handle for each simultaneous
transaction to be started.
2. Optionally creating and populating a TPB for each transaction.
60 INTERBASE 6
STARTING TRANSACTIONS
To use this typedef for declaring transaction handles in an application, include ibase.h in
each source file module:
#include <ibase.h>
Once a transaction is committed or rolled back, its handle can be assigned to a different
transaction in a subsequent call to isc_start_transaction(). If an application uses several
transactions, but only starts a subset of transactions at the same time, it is only necessary
to declare as many handles as there will be simultaneously active transactions. For
example, if an application starts a total of three transactions, but only runs two of them
at the same time, only two transaction handles need be declared.
API GUIDE 61
CHAPTER 5 WORKING WITH TRANSACTIONS
isc_tr_handle tr2;
. . .
/* Set transaction handles to zero before starting a transaction. */
tr1 = 0L;
tr2 = 0L;
62 INTERBASE 6
STARTING TRANSACTIONS
This example makes use of parameter constants defined in the InterBase header file,
ibase.h. The first element in every TPB must be the isc_tpb_version3 constant. The
following table lists available TPB constants, describes their purposes, and indicates
which constants are assigned as a default set of attributes when a NULL TPB pointer is
passed to isc_start_transaction():
Parameter Description
isc_tpb_version3 InterBase version 3 transaction
isc_tpb_consistency Table-locking transaction model
isc_tpb_concurrency High throughput, high concurrency transaction with acceptable
consistency; use of this parameter takes full advantage of the InterBase
multi-generational transaction model [Default]
isc_tpb_shared Concurrent, shared access of a specified table among all transactions; use
in conjunction with isc_tpb_lock_read and isc_tpb_lock_write to
establish the lock option [Default]
isc_tpb_protected Concurrent, restricted access of a specified table; use in conjunction with
isc_tpb_lock_read and isc_tpb_lock_write to establish the lock option
isc_tpb_wait Lock resolution specifies that the transaction is to wait until locked
resources are released before retrying an operation [Default]
isc_tpb_nowait Lock resolution specifies that the transaction is not to wait for locks to be
released, but instead, a lock conflict error should be returned immediately
isc_tpb_read Read-only access mode that allows a transaction only to select data from
tables
isc_tpb_write Read-write access mode of that allows a transaction to select, insert,
update, and delete table data [Default]
isc_tpb_lock_read Read-only access of a specified table. Use in conjunction with
isc_tpb_shared, isc_tpb_protected, and isc_tpb_exclusive to establish the
lock option.
isc_tpb_lock_write Read-write access of a specified table. Use in conjunction with
isc_tpb_shared, isc_tpb_protected, and isc_tpb_exclusive to establish the
lock option [Default]
TABLE 5.3 TPB constants
API GUIDE 63
CHAPTER 5 WORKING WITH TRANSACTIONS
Parameter Description
isc_tpb_read_committed High throughput, high concurrency transaction that can read changes
committed by other concurrent transactions. Use of this parameter takes
full advantage of the InterBase
multi-generational transaction model.
isc_tpb_rec_version Enables an isc_tpb_read_committed transaction to read the most recently
committed version of a record even if other, uncommitted versions are
pending.
isc_tpb_no_rec_version Enables an isc_tpb_read_committed transaction to read only the latest
committed version of a record. If an uncommitted version of a record is
pending and isc_tpb_wait is also specified, then the transaction waits for
the pending record to be committed or rolled back before proceeding.
Otherwise, a lock conflict error is reported at once.
TABLE 5.3 TPB constants (continued)
64 INTERBASE 6
STARTING TRANSACTIONS
g Table reservation optionally describes an access method and lock resolution for a
specified table that the transaction accesses. When table reservation is used, tables are
reserved for the specified access when the transaction is started, rather than when the
transaction actually accesses the table. Valid reservations are:
isc_tpb_shared, isc_tpb_lock_write
isc_tpb_shared, isc_tpb_lock_read
isc_tpb_protected, isc_tpb_lock_write
isc_tpb_protected, isc_tpb_lock_read
TPB parameters are described in detail in the following sections.
A TPB should specify only one access mode parameter. If more than one is specified, later
declarations override earlier ones.
If a TPB is declared that omits the access mode parameter, InterBase interprets
transaction access as read and write.
API GUIDE 65
CHAPTER 5 WORKING WITH TRANSACTIONS
ISC_TPB_CONCURRENCY
By default, after a transaction starts it cannot access committed changes to a table made
by other simultaneous transactions, even though it shares access to the table with them.
Such a transaction has an isolation level of isc_tpb_concurrency, meaning it can have
concurrent access to tables also accessed simultaneously by other transactions. The
following declaration creates a TPB specifying an isolation level of isc_tpb_concurrency:
static char isc_tpb[] = {isc_tpb_version3,
isc_tpb_write,
isc_tpb_concurrency};
ISC_TPB_READ_COMMITTED
A second isolation level, isc_tpb_read_committed, offers all the advantages of the
isc_tpb_concurrency isolation level and additionally enables a transaction to access
changes committed by other simultaneous transactions. Two other parameters,
isc_tpb_rec_version, and isc_tpb_no_rec_version, should be used with the
isc_tpb_read_committed parameter. They offer refined control over the committed
changes a transaction is permitted to access:
· isc_tpb_no_rec_version, the default refinement, specifies that a transaction can only
read the latest version of a row. If a change to a row is pending, but not yet committed,
the row cannot be read.
· isc_tpb_rec_version specifies that a transaction can read the latest committed version
of a row, even if a more recent uncommitted version is pending.
The following declaration creates a TPB with a read committed isolation level, and
specifies that the transaction can read the latest committed version of a row:
static char isc_tpb[] = {isc_tpb_version3,
isc_tpb_write,
isc_tpb_read_committed,
isc_tpb_rec_version};
ISC_TPB_CONSISTENCY
InterBase also supports a restrictive isolation level. isc_tpb_consistency prevents a
transaction from accessing tables if they are written to by other transactions; it also
prevents other transactions from writing to a table once this transaction writes to it. This
isolation level is designed to guarantee that if a transaction writes to a table before other
simultaneous read and write transactions, then only it can change a table’s data. Because
it essentially restricts (and often prevents) shared access to tables, isc_tpb_consistency
should be used with care.
66 INTERBASE 6
STARTING TRANSACTIONS
A TPB should only specify one isolation mode parameter (and one refinement parameter,
if isolation mode is isc_tpb_read_committed). If more than one is specified, later
declarations override earlier ones.
If a TPB is declared that omits the isolation mode parameter, InterBase interprets it as
isc_tpb_concurrency.
isc_tpb_concurrency,
isc_tpb_read_committed isc_tpb_consistency
isc_tpb_write isc_tpb_read isc_tpb_write isc_tpb_read
isc_tpb_write Some simultaneous — Conflicts Conflicts
concurrency, updates may conflict
read_committe
d isc_tpb_read — — — —
isc_tpb_write Conflicts — Conflicts Conflicts
consistency isc_tpb_read Conflicts — Conflicts —
TABLE 5.4 Isolation level interaction with read and write operations
API GUIDE 67
CHAPTER 5 WORKING WITH TRANSACTIONS
g isc_tpb_wait, the default, specifies that the transaction should wait until locked resources
are released. Once the resources are released, the transaction retries its operation.
g isc_tpb_nowait specifies that the transaction should return a lock conflict error without
waiting for locks to be released.
For example, the following declaration creates a TPB with write access, a concurrency
isolation mode, and a lock resolution of isc_tpb_nowait:
static char isc_tpb[] = {isc_tpb_version3,
isc_tpb_write,
isc_tpb_concurrency,
isc_tpb_nowait};
A TPB should only specify one lock resolution parameter. If more than one is specified,
later declarations override earlier ones.
If a TPB is declared that omits the lock resolution parameter, InterBase interprets it as
isc_tpb_concurrency.
68 INTERBASE 6
STARTING TRANSACTIONS
· isc_tpb_shared, isc_tpb_lock_read, which permits any transaction to read data, and any
transaction with an access mode of isc_tpb_write to update. This is the most liberal
reservation mode.
· isc_tpb_protected, isc_tpb_lock_write, which prevents other transactions from
updating. Other transactions with isolation levels of isc_tpb_concurrency or
isc_tpb_read_committed can read data, but only this transaction can update.
· isc_tpb_protected, isc_tpb_lock_read, which prevents all transactions from updating,
but permits all transactions to read data.
The name of the table to reserve must immediately follow the reservation parameters. For
example, the following TPB declaration reserves a table, EMPLOYEE, for protected read
access:
static char isc_tpb[] = {isc_tpb_version3,
isc_tpb_write,
isc_tpb_concurrency,
isc_tpb_nowait,
isc_tpb_protected, isc_tpb_lock_read, "EMPLOYEE"};
Several tables can be reserved at the same time. The following declaration illustrates how
two tables are reserved, one for protected read, the other for protected write:
static char isc_tpb[] = {isc_tpb_version3,
isc_tpb_write,
isc_tpb_concurrency,
isc_tpb_nowait,
isc_tpb_protected, isc_tpb_lock_read, "COUNTRY",
isc_tpb_protected, isc_tpb_lock_write, "EMPLOYEE"};
API GUIDE 69
CHAPTER 5 WORKING WITH TRANSACTIONS
Calling isc_start_transaction( )
Once transaction handles and TPBs are prepared, a transaction can be started by calling
isc_start_transaction() using the following syntax:
ISC_STATUS isc_start_transaction(
ISC_STATUS *status vector,
isc_tr_handle *trans_handle,
short db_count,
isc_db_handle *&db_handle,
unsigned short tpb_length,
char *tpb_ad);
For a transaction that runs against a single database, set db_count to 1. db_handle
should be a database handle set with a previous call to isc_attach_database(). tpb_length
is the size of the TPB passed in the next parameter, and tpb_ad is the address of the TPB.
The following code illustrates a typical call to isc_start_transaction():
#include <ibase.h>
. . .
ISC_STATUS status_vector[20];
isc_db_handle db1;
isc_tr_handle tr1;
static char isc_tbp[] = {isc_tpb_version3,
isc_tpb_write,
isc_tpb_concurrency,
isc_tpb_wait};
. . .
/* Initialize database and transaction handles here. */
db1 = 0L;
tr1 = 0L;
. . .
/* Code for attaching to database here is omitted. */
isc_start_transaction(status_vector,
&tr1,
1,
&db1,
(unsigned short) sizeof(isc_tpb),
isc_tpb);
70 INTERBASE 6
STARTING TRANSACTIONS
A transaction can be opened against multiple databases. To do so, set the db_count
parameter to the number of databases against which the transaction runs, then for each
database, repeat the db_handle, tpb_length, and tpb_ad parameters as a group once for
each database. For example, the following code fragment assumes that two databases are
connected when the transaction is started:
isc_start_transaction(status_vector,
&tr1,
2,
&db1,
(unsigned short) sizeof(isc_tpb),
&tpb);
&db2,
(unsigned short) sizeof(isc_tpb),
&tpb);
Calling isc_start_multiple( )
An alternate method for starting a transaction against multiple databases is to use
isc_start_multiple(). Using isc_start_multiple() is not recommended unless you:
g Are using a language that does not support a variable number of arguments in a function
call.
g Do not know how many databases you want to attach to when coding the start of a
transaction.
C programmers should seldom need to use this function.
isc_start_multiple() passes information about each target database to InterBase through
an array of transaction existence blocks (TEBs). There must be one TEB for each database
against which a transaction runs. A TEB is a structure you must declare in your
applications as follows:
typdef struct {
long *db_ptr;
long tpb_len;
char *tpb_ptr;
} ISC_TEB;
API GUIDE 71
CHAPTER 5 WORKING WITH TRANSACTIONS
Once an array of TEBs is declared, and corresponding TBPs are created and populated
for each database, values may be assigned to the appropriate fields in the TEBs. For
example, the following code illustrates how two TEBs are filled:
. . .
ISC_STATUS status_vector[20];
isc_db_handle db1, db2;
isc_tr_handle trans;
ISC_TEB teb_array[2];
. . .
db1 = db2 = 0L;
trans = 0L;
/* Code assumes that two TPBs, isc_tpb1, and isc_tpb2, are created
here. */
/* Code assumes databases are attached here. */
/* assign values to TEB array */
teb_array[0].db_ptr = &db1;
teb_array[0].tpb_len = sizeof(isc_tpb1);
teb_array[0].tpb_ptr = isc_tpb1;
teb_array[1].db_ptr = &db2;
teb_array[1].tpb_len = sizeof(isc_tpb2);
teb_array[1].tpb_ptr = isc_tpb2;
. . .
72 INTERBASE 6
ENDING TRANSACTIONS
After the TEBs are loaded with values, isc_start_multiple() can be called using the
following syntax:
ISC_STATUS isc_start_multiple(
ISC_STATUS *status_vector,
isc_tr_handle *trans_handle,
short db_handle_count,
void *teb_vector_address);
Ending transactions
When a transaction’s tasks are complete, or an error prevents a transaction from
completing, the transaction must be ended to set the database to a consistent state. There
are two API functions that end transactions:
g isc_commit_transaction() makes a transaction’s changes permanent in the database. For
transactions that span databases, this function performs an automatic, two-phase commit
to ensure that all changes are made successfully.
API GUIDE 73
CHAPTER 5 WORKING WITH TRANSACTIONS
IMPORTANT If the program ends before a transaction ends, a transaction is automatically rolled back,
but databases are not closed. If a program ends without closing the database, data loss
or corruption is possible. Therefore, open databases should always be closed by issuing
an explicit call to isc_detach_database().
For more information about detaching from a database, see Chapter 4, “Working with
Databases.”
Using isc_commit_transaction( )
Use isc_commit_transaction() to write transaction changes permanently to a database.
isc_commit_transaction() closes the record streams associated with the transaction,
resets the transaction name to zero, and frees system resources assigned to the
transaction for other uses. The complete syntax for isc_commit_transaction() is:
ISC_STATUS isc_commit_transaction(
ISC_STATUS *status_vector,
isc_tr_handle *trans_handle);
74 INTERBASE 6
ENDING TRANSACTIONS
where status_vector is a pointer to a previously declared error status vector, and trans is
a pointer to a previously declared and initialized transaction handle.
Tip Even transactions started with an access mode of isc_tpb_read should be ended with a
call to isc_commit_transaction() rather than isc_rollback_transaction(). The database
is not changed, but the overhead required to start subsequent transactions is greatly
reduced.
4 Using isc_commit_retaining()
To write transaction changes to the database without establishing a new transaction
context—the names, system resources, and current state of cursors used in a
transaction—use isc_commit_retaining() instead of isc_commit_transaction(). In a
busy, multi-user environment, maintaining the transaction context for each user speeds
up processing and uses fewer system resources than closing and starting a new
transaction for each action. The complete syntax for isc_commit_retaining() is:
ISC_STATUS isc_commit_retaining(
ISC_STATUS *status_vector,
isc_tr_handle *trans_handle);
isc_commit_retaining() writes all pending changes to the database, ends the current
transaction without closing its record stream and cursors and without freeing its system
resources, then starts a new transaction and assigns the existing record streams and
system resources to the new transaction.
For example, the following call commits a specified transaction, preserving the current
cursor status and system resources:
isc_commit_retaining(status_vector, &trans);
where status_vector is a pointer to a previously declared error status vector, and trans is
a pointer to a previously declared and initialized transaction handle.
A call to isc_rollback_transaction() issued after isc_commit_retaining() only rolls back
updates and writes occurring after the call to isc_commit_retaining().
API GUIDE 75
CHAPTER 5 WORKING WITH TRANSACTIONS
4 Using isc_prepare_transaction()
When a transaction is committed against multiple databases using
isc_commit_transaction(), InterBase automatically performs a two-phase commit.
During the first phase of the commit, the InterBase engine polls all database participants
to make sure they are still available, writes a message describing the transaction to the
RDB$TRANSACTION_DESCRIPTION field of the RDB$TRANSACTION system table, then puts the
transaction into a limbo state. It is during the second phase that transaction changes are
actually committed to the database.
Some applications may have their own, additional requirements to make of the two-phase
commit. These applications can call isc_prepare_transaction() to execute the first phase
of the two-phase commit, then perform their own, additional tasks before completing the
commit with a call to isc_commit_transaction().
The syntax for isc_prepare_transaction() is:
ISC_STATUS isc_prepare_transaction(
ISC_STATUS *status_vector,
isc_tr_handle *trans_handle);
For example, the following code fragment illustrates how an application might call
isc_prepare_transaction(), then its own routines, before completing a commit with
isc_commit_transaction():
ISC_STATUS status_vector[20];
isc_db_handle db1;
isc_tr_handle trans;
. . .
/* Initialize handles. */
db1 = 0L;
trans = 0L;
. . .
/* Code assumes a database is attached here, */
/* and a transaction started. */
. . .
/* Perform first phase of two-phase commit. */
isc_prepare_transaction(status_vector, &trans);
/* Application does its own processing here. */
my_app_function();
/* Now complete the two-phase commit. */
isc_commit_transaction(status_vector, &trans);
76 INTERBASE 6
ENDING TRANSACTIONS
IMPORTANT It is generally a dangerous practice to delay the second phase of the commit after
completing the first, because delays increase the chance that network or server problems
can occur between phases.
Using isc_prepare_transaction2( )
Like isc_prepare_transaction(), isc_prepare_transaction2() performs the first phase of a
two-phase commit, except that isc_prepare_transaction2() enables
an application to supply its own transaction description for insertion into the
RDB$TRANSACTION_DESCRIPTION field of the RDB$TRANSACTION
system table.
IMPORTANT Do not use this call without first examining and understanding the information
InterBase stores in RDB$TRANSACTION_DESCRIPTION during an automatic, two-phase
commit. Storage of improper or incomplete information can prevent database recovery
if the two-phase commit fails.
See page 363 for the complete syntax of isc_prepare_transaction2().
Using isc_rollback_transaction( )
Use isc_rollback_transaction() to restore the database to its condition prior to the start
of the transaction. isc_rollback_transaction() also closes the record streams associated
with the transaction, resets the transaction name to zero, and frees system resources
assigned to the transaction for other uses. isc_rollback_transaction() typically appears
in error-handling routines. The syntax for isc_rollback_transaction() is:
ISC_STATUS isc_rollback_transaction(
ISC_STATUS *status_vector,
isc_tr_handle *trans_handle);
API GUIDE 77
CHAPTER 5 WORKING WITH TRANSACTIONS
78 INTERBASE 6
CHAPTER
This chapter describes how to use API dynamic SQL (DSQL) functions to handle
dynamically created SQL statements for data definition and manipulation. Using
low-level API calls enables client applications to build SQL statements or solicit them
from end users at runtime, providing end users with a familiar database interface. It also
provides applications developers low-level access to InterBase features, such as multiple
databases, not normally available at a higher level with embedded DSQL statements. For
example, the InterBase isql utility is a DSQL application built on low-level API calls.
All API DSQL function names begin with “isc_dsql” to make it easier to distinguish them
from other API calls.
API GUIDE 79
CHAPTER 6 WORKING WITH DYNAMIC SQL
g Programming methods that use these statements and facilities to process SQL statements
at runtime.
These steps are described in detail throughout this chapter.
Accessing databases
The InterBase API permits applications to attach to multiple databases simultaneously
using database handles. Database handles must be declared and initialized when an
application is compiled. Separate database handles should be supplied and initialized for
each database accessed simultaneously. For example, the following code creates a single
handle, db1, and initializes it to zero:
#include <ibase.h>
isc_db_handle db1;
. . .
db1 = 0L;
80 INTERBASE 6
DSQL API LIMITATIONS
. . .
char dbname[129];
ISC_STATUS status_vector[20];
. . .
prompt_user("Name of database to open: ");
gets(dbname);
isc_attach_database(status_vector, 0, dbname, &db1, NULL, NULL);
For more information about API function calls for databases, see Chapter 4, “Working
with Databases.”
Handling transactions
InterBase requires that all transaction handles be declared when an application is
compiled. Once fixed at compile time, transaction handles cannot be changed at runtime,
nor can new handles be declared dynamically at runtime. Most API functions that process
SQL statements at runtime, such as isc_dsql_describe(), isc_dsql_describe_bind(),
isc_dsql_execute(), isc_dsql_execute2(), isc_dsql_execute_immediate(),
isc_dsql_exec_immed2(), and isc_dsql_prepare(), support the inclusion of a transaction
handle parameter. The SQL statements processed by these functions cannot pass
transaction handles even if the SQL syntax for the statement permits the use of a
TRANSACTION clause.
Before a transaction handle can be used, it must be declared and initialized to zero. The
following code declares, initializes, and uses a transaction handle in an API call that
allocates and prepares an SQL statement for execution:
#include <ibase.h>
. . .
isc_tr_handle trans; /* Declare a transaction handle. */
isc_stmt_handle stmt; /* Declare a statement handle. */
char *sql_stmt = "SELECT * FROM EMPLOYEE";
isc_db_handle db1;
ISC_STATUS status_vector[20];
. . .
API GUIDE 81
CHAPTER 6 WORKING WITH DYNAMIC SQL
Note The SQL SET TRANSACTION statement cannot be prepared with isc_dsql_prepare(),
but it can be processed with isc_dsql_execute_immediate() if:
1. Previous transactions are first committed or rolled back.
2. The transaction handle is set to NULL.
For more information about using SQL statements, see the Embedded SQL Guide. For
more information about SQL statement syntax, see the Language Reference.
Creating a database
To create a new database in an API application:
1. Detach from any currently attached databases with isc_detach_database().
Detaching from a database automatically sets its database handle to NULL.
2. Build the CREATE DATABASE statement to process.
3. Execute the statement with isc_dsql_execute_immediate() or
isc_dsql_exec_immed2().
For example, the following statements disconnect from any currently attached databases,
and create a new database. Any existing database handles are set to NULL, so that they
can be used to connect to the new database in future DSQL statements.
char *str = "CREATE DATABASE \"new_emp.gdb\"";
. . .
isc_detach_database(status_vector, &db1);
isc_dsql_execute_immediate(status_vector, &db1, &trans, 0, str, 1,
NULL);
82 INTERBASE 6
WRITING AN API APPLICATION TO PROCESS SQL STATEMENTS
API GUIDE 83
CHAPTER 6 WORKING WITH DYNAMIC SQL
Statement Statement
CLOSE DECLARE CURSOR
DESCRIBE EXECUTE
OPEN PREPARE
These statements are used to process DSQL requests or to handle SQL cursors, which
must always be specified when an application is written. Attempting to use them with
DSQL results in run-time errors.
Note The semicolon that appears at the end of this char declaration is a C terminator,
and not part of the SQL statement string.
84 INTERBASE 6
UNDERSTANDING THE XSQLDA
API GUIDE 85
CHAPTER 6 WORKING WITH DYNAMIC SQL
Applications do not declare instances of the XSQLVAR ahead of time, but must, instead,
dynamically allocate storage for the proper number of XSQLVAR structures required for
each DSQL statement before it is executed, then deallocate it, as appropriate, after
statement execution.
The following figure illustrates the relationship between the XSQLDA and the XSQLVAR:
86 INTERBASE 6
UNDERSTANDING THE XSQLDA
An input XSQLDA consists of a single XSQLDA structure and one XSQLVAR structure for each
input parameter. An output XSQLDA also consists of one XSQLDA structure and one XSQLVAR
structure for each data item returned by the statement. An XSQLDA and its associated
XSQLVAR structures are allocated as a single block of contiguous memory.
The isc_dsql_prepare(), isc_dsql_describe(), and isc_dsql_describe_bind() functions can
be used to determine the proper number of XSQLVAR structures to allocate, and the
XSQLDA_LENGTH macro can be used to allocate the proper amount of space. For more
information about the XSQLDA_LENGTH macro, see “Using the XSQLDA_LENGTH macro”
on page 90.
API GUIDE 87
CHAPTER 6 WORKING WITH DYNAMIC SQL
The following table describes the fields that comprise the XSQLVAR structure:
88 INTERBASE 6
UNDERSTANDING THE XSQLDA
Input descriptors
Input descriptors are used to process SQL statement strings that contain parameters.
Before an application can execute a statement with parameters, it must supply values for
them. The application indicates the number of parameters passed in the XSQLDA sqld
field, then describes each parameter in a separate XSQLVAR structure. For example, the
following statement string contains two parameters, so an application must set sqld to 2,
and describe each parameter:
char *str = "UPDATE DEPARTMENT SET BUDGET = ? WHERE LOCATION = ?";
When the statement is executed, the first XSQLVAR supplies information about the BUDGET
value, and the second XSQLVAR supplies the LOCATION value.
For more information about using input descriptors, see “DSQL programming
methods” on page 96.
Output descriptors
Output descriptors return values from an executed query to an application. The sqld field
of the XSQLDA indicates how many values were returned. Each value is stored in a
separate XSQLVAR structure. The XSQLDA sqlvar field points to the first of these XSQLVAR
structures. The following statement string requires an output descriptor:
char *str = "SELECT * FROM CUSTOMER WHERE CUST_NO > 100";
API GUIDE 89
CHAPTER 6 WORKING WITH DYNAMIC SQL
For information about retrieving information from an output descriptor, see “DSQL
programming methods” on page 96.
For more information about using the XSQLDA_LENGTH macro, see “DSQL programming
methods” on page 96.
SQL sqlind
datatype Macro expression C datatype or typedef used?
Array SQL_ARRAY ISC_QUAD No
Array SQL_ARRAY + 1 ISC_QUAD Yes
Blob SQL_BLOB ISC_QUAD No
TABLE 6.4 SQL datatypes, macro expressions, and C datatypes
90 INTERBASE 6
UNDERSTANDING THE XSQLDA
SQL sqlind
datatype Macro expression C datatype or typedef used?
BLOB SQL_BLOB + 1 ISC_QUAD Yes
CHAR SQL_TEXT char[] No
CHAR SQL_TEXT + 1 char[] Yes
DATE SQL_DATE ISC_DATE No
DATE SQL_DATE + 1 ISC_DATE Yes
DECIMAL SQL_SHORT, SQL_LONG, SQL_DOUBLE, or SQL_INT64 int, long, double, or ISC_INT64 No
DECIMAL SQL_SHORT + 1, SQL_LONG + 1, SQL_DOUBLE + 1, int, long, double, or ISC_INT64 Yes
or SQL_INT64 + 1
API GUIDE 91
CHAPTER 6 WORKING WITH DYNAMIC SQL
SQL sqlind
datatype Macro expression C datatype or typedef used?
TIMESTAMP SQL_TIMESTAMP + 1 ISC_TIMESTAMP Yes
VARCHAR SQL_VARYING First 2 bytes: short containing the length of No
the character string; remaining bytes: char[]
VARCHAR SQL_VARYING + 1 First 2 bytes: short containing the length of Yes
the character string; remaining bytes: char[]
TABLE 6.4 SQL datatypes, macro expressions, and C datatypes (continued)
Note DECIMAL and NUMERIC datatypes are stored internally as SMALLINT, INTEGER, DOUBLE
PRECISION, or 64-bit integer datatypes. To specify the correct macro expression to provide
for a DECIMAL or NUMERIC column, use isql to examine the column definition in the table
to see how InterBase is storing column data, then choose a corresponding macro
expression.
The datatype information for a parameter or select-list item is contained in the sqltype
field of the XSQLVAR structure. The value contained in sqltype provides two pieces of
information:
g The datatype of the parameter or select-list item.
g Whether sqlind is used to indicate NULL values. If sqlind is used, its value specifies
whether the parameter or select-list item is NULL (–1), or not NULL (0).
For example, if sqltype equals SQL_TEXT, the parameter or select-list item is a CHAR that
does not use sqlind to check for a NULL value (because, in theory, NULL values are not
allowed for it). If sqltype equals SQL_TEXT + 1, then sqlind can be checked to see if the
parameter or select-list item is NULL.
Tip The C language expression, sqltype & 1, provides a useful test of whether a parameter or
select-list item can contain a NULL. The expression evaluates to 0 if the parameter or
select-list item cannot contain a NULL, and 1 if the parameter or select-list item can
contain a NULL. The following code fragment demonstrates how to use the expression:
if (sqltype & 1 == 0)
{
/* parameter or select-list item that CANNOT contain a NULL */
}
else
{
/* parameter or select-list item CAN contain a NULL */
}
92 INTERBASE 6
UNDERSTANDING THE XSQLDA
API GUIDE 93
CHAPTER 6 WORKING WITH DYNAMIC SQL
Coercing datatypes
Sometimes when processing DSQL input parameters and select-list items, it is desirable
or necessary to translate one datatype to another. This process is referred to as datatype
coercion. For example, datatype coercion is often used when parameters or select-list
items are of type VARCHAR. The first two bytes of VARCHAR data contain string length
information, while the remainder of the data is the string to process. By coercing the data
from SQL_VARYING to SQL_TEXT, data processing can be simplified.
Coercion can only be from one compatible datatype to another. For example,
SQL_VARYING to SQL_TEXT, or SQL_SHORT to SQL_LONG.
After coercing a character datatype, provide proper storage space for it. The XSQLVAR field,
sqllen, contains information about the size of the uncoerced data.
Set the XSQLVAR sqldata field to the address of the data.
IMPORTANT Do not coerce a larger datatype to a smaller one. Data can be lost in such a translation.
94 INTERBASE 6
UNDERSTANDING THE XSQLDA
API GUIDE 95
CHAPTER 6 WORKING WITH DYNAMIC SQL
4 Using isc_dsql_execute_immediate( )
1. To execute a statement string a single time, use
isc_dsql_execute_immediate():
2. Elicit a statement string from the user or create one that contains the SQL
statement to be processed. For example, the following statement creates an
SQL statement string:
char *str = "UPDATE DEPARTMENT SET BUDGET = BUDGET * 1.05";
96 INTERBASE 6
DSQL PROGRAMMING METHODS
3. Parse the statement string with isc_dsql_prepare(). This sets the statement
handle (stmt) to refer to the parsed format. The statement handle is used in
subsequent calls to isc_dsql_execute():
isc_dsql_prepare(status_vector, &trans, &stmt, 0, str, 1, NULL);
API GUIDE 97
CHAPTER 6 WORKING WITH DYNAMIC SQL
Declaring a pointer to the XSQLVAR structure is not necessary, but can simplify
referencing the structure in subsequent statements.
3. Allocate memory for the XSQLDA using the XSQLDA_LENGTH macro. The
following statement allocates storage for in_sqlda:
in_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(10));
In this statement space for 10 XSQLVAR structures is allocated, allowing the XSQLDA to
accommodate up to 10 parameters.
4. Set the version field of the XSQLDA to SQLDA_VERSION1, and set the sqln field
to indicate the number of XSQLVAR structures allocated:
in_sqlda->version = SQLDA_VERSION1;
in_sqlda->sqln = 10;
98 INTERBASE 6
DSQL PROGRAMMING METHODS
To prepare and execute a non-query statement string with parameters, follow these steps:
1. Elicit a statement string from the user or create one that contains the SQL
statement to be processed. For example, the following statement creates an
SQL statement string with placeholder parameters:
char *str = "UPDATE DEPARTMENT SET BUDGET = ?, LOCATION = ?";
This statement string contains two parameters: a value to be assigned to the BUDGET
column and a value to be assigned to the LOCATION column.
2. Declare and initialize an SQL statement handle, then allocate it with
isc_dsql_allocate():
isc_stmt_handle stmt; /* Declare a statement handle. */
stmt = NULL; /* Set handle to NULL before allocation. */
. . .
isc_dsql_allocate_statement(status_vector, &db1, &stmt);
3. Parse the statement string with isc_dsql_prepare(). This sets the statement
handle (stmt) to refer to the parsed format. The statement handle is used in
subsequent calls to isc_dsql_describe_bind() and isc_dsql_execute():
isc_dsql_prepare(status_vector, &trans, &stmt, 0, str, 1,
in_sqlda);
5. Compare the value of the sqln field of the XSQLDA to the value of the sqld field
to make sure enough XSQLVARs are allocated to hold information about each
parameter. sqln should be at least as large as sqld. If not, free the storage
previously allocated to the input descriptor, reallocate storage to reflect the
number of parameters specified by sqld, reset sqln and version, then execute
isc_dsql_describe_bind() again:
if (in_sqlda->sqld > in_sqlda->sqln)
{
n = in_sqlda->sqld;
free(in_sqlda);
in_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(n));
in_sqlda->sqln = n
in_sqlda->version = SQLDA_VERSION1;
isc_dsql_describe_bind(status_vector, &stmt, 1, in_sqlda);
}
API GUIDE 99
CHAPTER 6 WORKING WITH DYNAMIC SQL
100 INTERBASE 6
DSQL PROGRAMMING METHODS
For more information about datatype coercion and NULL indicators, see “Coercing
datatypes” on page 94.
7. Execute the named statement string with isc_dsql_execute(). For example,
the following statement executes a statement string named stmt:
isc_dsql_execute(status_vector, &trans, &stmt, 1, in_sqlda);
Declaring a pointer to the XSQLVAR structure is not necessary, but can simplify
referencing the structure in subsequent statements.
3. Allocate memory for the XSQLDA using the XSQLDA_LENGTH macro. The
following statement allocates storage for out_sqlda:
out_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(10));
Space for ten XSQLVAR structures is allocated in this statement, enabling the XSQLDA to
accommodate up to ten select-list items.
4. Set the version field of the XSQLDA to SQLDA_VERSION1, and set the sqln field
of the XSQLDA to indicate the number of XSQLVAR structures allocated:
out_sqlda->version = SQLDA_VERSION1;
out_sqlda->sqln = 10;
The statement appears to have only one select-list item (*). The asterisk is a wildcard
symbol that stands for all of the columns in the table, so the actual number of items
returned equals the number of columns in the table.
2. Declare and initialize an SQL statement handle, then allocate it with
isc_dsql_allocate():
isc_stmt_handle stmt; /* Declare a statement handle. */
stmt = NULL; /* Set handle to NULL before allocation. */
. . .
isc_dsql_allocate_statement(status_vector, &db1, &stmt);
102 INTERBASE 6
DSQL PROGRAMMING METHODS
3. Parse the statement string with isc_dsql_prepare(). This sets the statement
handle (stmt) to refer to the parsed format. The statement handle is used in
subsequent calls to statements such as isc_dsql_describe() and
isc_dsql_execute():
isc_dsql_prepare(status_vector, &trans, &stmt, 0, str, 1, NULL);
4. Use isc_dsql_describe() to fill the output XSQLDA with information about the
select-list items returned by the statement:
isc_dsql_describe(status_vector, &trans, &stmt, out_sqlda);
5. Compare the sqln field of the XSQLDA to the sqld field to determine if the
output descriptor can accommodate the number of select-list items specified
in the statement. If not, free the storage previously allocated to the output
descriptor, reallocate storage to reflect the number of select-list items
specified by sqld, reset sqln and version, then execute isc_dsql_describe()
again:
if (out_sqlda->sqld > out_sqlda->sqln)
{
n = out_sqlda->sqld;
free(out_sqlda);
out_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(n));
out_sqlda->sqln = n;
out_sqlda->version = SQLDA_VERSION1;
isc_dsql_describe(status_vector, &trans, 1, out_sqlda);
}
case SQL_VARYING:
var->sqltype = SQL_TEXT;
var->sqldata = (char *)malloc(sizeof(char)*var->sqllen + 2);
break;
case SQL_TEXT:
var->sqldata = (char *)malloc(sizeof(char)*var->sqllen);
break;
case SQL_LONG:
var->sqldata = (char *)malloc(sizeof(long));
break;
. . .
/* process remaining types */
} /* end of switch statements */
if (sqltype & 1)
{
/* allocate variable to hold NULL status */
var->sqlind = (short *)malloc(sizeof(short));
}
} /* end of for loop */
For more information about datatype coercion and NULL indicators, see “Coercing
datatypes” on page 94.
104 INTERBASE 6
DSQL PROGRAMMING METHODS
Opening the cursor causes the statement string to be executed, and an active set of
rows to be retrieved.
3. Fetch one row at a time and process the select-list items (columns) it contains
with isc_dsql_fetch(). For example, the following loops retrieve one row at a
time from dyn_cursor and process each item in the retrieved row with an
application-specific function called process_column():
while ((fetch_stat =
isc_dsql_fetch(status_vector, &stmt, 1, out_sqlda))
== 0)
{
for (i = 0; i < out_sqlda->sqld; i++)
{
process_column(sqlda->sqlvar[i]);
}
}
if (fetch_stat != 100L)
{
/* isc_dsql_fetch returns 100 if no more rows remain to be
retrieved */
SQLCODE = isc_sqlcode(status_vector);
isc_print_sqlerror(SQLCODE, status_vector);
return(1);
}
The process_column() function mentioned in this example processes each returned
select-list item. The following skeleton code illustrates how such a function can be set
up:
void process_column(XSQLVAR *var)
{
/* test for NULL value */
if ((var->sqltype & 1) && (*(var->sqlind) = -1))
{
/* process the NULL value here */
}
else
{
/* process the data instead */
}
. . .
}
4. When all the rows are fetched, close the cursor with
isc_dsql_free_statement():
isc_dsql_free_statement(status_vector, &stmt, DSQL_close);
106 INTERBASE 6
DSQL PROGRAMMING METHODS
Declaring a pointer to the XSQLVAR structure is not necessary, but can simplify
referencing the structure in subsequent statements.
3. Allocate memory for the XSQLDA using the XSQLDA_LENGTH macro. The
following statement allocates storage for in_slqda:
in_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(10));
In this statement, space for 10 XSQLVAR structures is allocated, allowing the XSQLDA to
accommodate up to 10 input parameters. Once structures are allocated, assign values
to the sqldata fields.
4. Set the version field of the XSQLDA to SQLDA_VERSION1, and set the sqln field
of the XSQLDA to indicate the number of XSQLVAR structures allocated:
in_sqlda->version = SQLDA_VERSION1;
in_sqlda->sqln = 10;
Declaring a pointer to the XSQLVAR structure is not necessary, but can simplify
referencing the structure in subsequent statements.
3. Allocate memory for the XSQLDA using the XSQLDA_LENGTH macro. The
following statement allocates storage for out_sqlda:
out_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(10));
Space for ten XSQLVAR structures is allocated in this statement, enabling the XSQLDA to
accommodate up to ten select-list items.
4. Set the version field of the XSQLDA to SQLDA_VERSION1, and set the sqln field
of the XSQLDA to indicate the number of XSQLVAR structures allocated:
out_sqlda->version = SQLDA_VERSION1;
out_sqlda->sqln = 10;
This statement string contains two parameters: a value to be assigned to the BUDGET
column and a value to be assigned to the LOCATION column.
2. Declare and initialize an SQL statement handle, then allocate it with
isc_dsql_allocate():
isc_stmt_handle stmt; /* Declare a statement handle. */
stmt = NULL; /* Set handle to NULL before allocation. */
. . .
isc_dsql_allocate_statement(status_vector, &db1, &stmt);
3. Prepare the statement string with isc_dsql_prepare(). This sets the statement
handle (stmt) to refer to the parsed format. The statement handle is used in
subsequent calls to isc_dsql_describe(), isc_dsql_describe_bind(), and
isc_dsql_execute2():
isc_dsql_prepare(status_vector, &trans, &stmt, 0,
str, 1, out_xsqlda);
108 INTERBASE 6
DSQL PROGRAMMING METHODS
5. Compare the sqln field of the XSQLDA to the sqld field to determine if the input
descriptor can accommodate the number of parameters contained in the
statement. If not, free the storage previously allocated to the input descriptor,
reallocate storage to reflect the number of parameters specified by sqld, reset
sqln and version, then execute isc_dsql_describe_bind() again:
if (in_sqlda->sqld > in_sqlda->sqln)
{
n = in_sqlda->sqld;
free(in_sqlda);
in_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(n));
in_sqlda->sqln = n;
in_sqlda->version = SQLDA_VERSION1;
isc_dsql_decribe_bind(status_vector, &stmt, 1, in_xsqlda);
}
case SQL_TEXT:
var->sqldata = (char *)malloc(sizeof(char)*var->sqllen);
/* Provide a value for the parameter. See case SQL_LONG. */
. . .
break;
case SQL_LONG:
var->sqldata = (char *)malloc(sizeof(long));
/* Provide a value for the parameter. */
*(long *)(var->sqldata) = 17;
break;
. . .
} /* end of switch statement */
if (sqltype & 1)
{
/* allocate variable to hold NULL status */
var->sqlind = (short *)malloc(sizeof(short));
}
} /* end of for loop */
For more information about datatype coercion and NULL indicators, see “Coercing
datatypes” on page 94.
7. Use isc_dsql_describe() to fill the output XSQLDA with information about the
select-list items returned by the statement:
isc_dsql_describe(status_vector, &trans, &stmt, out_xsqlda);
8. Compare the sqln field of the XSQLDA to the sqld field to determine if the
output descriptor can accommodate the number of select-list items specified
in the statement. If not, free the storage previously allocated to the output
descriptor, reallocate storage to reflect the number of select-list items
specified by sqld, reset sqln and version, and execute DESCRIBE OUTPUT again:
if (out_sqlda->sqld > out_sqlda->sqln)
{
n = out_sqlda->sqld;
free(out_sqlda);
out_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(n));
out_sqlda->sqln = n;
out_sqlda->version = SQLDA_VERSION1;
isc_dsql_describe(status_vector, &trans, &stmt, out_xsqlda);
}
110 INTERBASE 6
DSQL PROGRAMMING METHODS
For more information about datatype coercion and NULL indicators, see “Coercing
datatypes” on page 94.
A looping construct is used to fetch a single row at a time from the cursor and to process
each select-list item (column) in that row before the next row is fetched.
To execute a statement string within the context of a cursor and retrieve rows of select-list
items, follow these steps:
1. Execute the statement with isc_dsql_execute2():
isc_dsql_execute2(status_vector, &trans, &stmt, 1,
in_xsqlda, out_xsqlda);
Opening the cursor causes the statement string to be executed, and an active set of
rows to be retrieved.
3. Fetch one row at a time with isc_dsql_fetch() and process the select-list items
(columns) it contains. For example, the following loops retrieve one row at
a time from dyn_cursor and process each item in the retrieved row with an
application-specific function called process_column():
while ((fetch_stat =
isc_dsql_fetch(status_vector, &stmt, 1, out_sqlda)) == 0)
{
for (i = 0; i < out_sqlda->sqld; i++)
{
process_column(sqlda->sqlvar[i]);
}
}
if (fetch_stat != 100L)
{
/* isc_dsql_fetch returns 100 if no more rows remain to be
retrieved */
SQLCODE = isc_sqlcode(status_vector);
isc_print_sqlerror(SQLCODE, status_vector);
return(1);
}
4. When all the rows are fetched, close the cursor with
isc_dsql_free_statement():
isc_dsql_free_statement(status_vector, &stmt, DSQL_close);
112 INTERBASE 6
DETERMINING AN UNKNOWN STATEMENT TYPE AT RUNTIME
Note Additional information item macros for requested items can be found in ibase.h
under the comment, “SQL information items.”
The result buffer must be large enough to contain any data returned by the call. The
proper size for this buffer depends on the information requested. If not enough space is
allocated, then isc_dsql_sql_info() puts the predefined value, isc_info_truncated, in the
last byte of the result buffer. Generally, when requesting statement type information, 8
bytes is a sufficient buffer size. Declaring a larger than necessary buffer is also safe. A
request to identify a statement type returns the following information in the result buffer:
1. One byte containing isc_info_sql_stmt_type.
2. Two bytes containing a number, n, telling how many bytes compose the
subsequent value.
3. One or two bytes specifying the statement type. The following table lists the
statement types that can be returned:
114 INTERBASE 6
DETERMINING AN UNKNOWN STATEMENT TYPE AT RUNTIME
Note All information about a statement except its type can be more easily determined by
calling functions other than isc_dsql_sql_info(). For example, to determine the
information to fill in an input XSQLDA, call isc_dsql_describe_bind(). To fill in an output
XSQLDA, call isc_dsql_prepare() or isc_dsql_describe().
116 INTERBASE 6
CHAPTER
The following table alphabetically lists the API functions for working with Blob data. The
functions will be described and demonstrated in the remainder of this chapter.
Function Purpose
isc_blob_default_desc() Loads a Blob descriptor with default information about a Blob,
including its subtype, character set, and segment size
isc_blob_gen_bpb() Generates a Blob parameter buffer (BPB) from source and target Blob
descriptors to allow dynamic access to Blob subtype and character set
information
isc_blob_info() Returns information about an open Blob
isc_blob_lookup_desc() Determines the subtype, character set, and segment size of a Blob,
given a table name and Blob column name
isc_blob_set_desc() Initializes a Blob descriptor from parameters passed to it
isc_cancel_blob() Discards a Blob
isc_close_blob() Closes an open Blob
isc_create_blob2() Creates and opens a Blob for write access, and optionally specifies a
filter to be used to translate the Blob from one subtype to another
isc_get_segment() Retrieves data from a Blob column in a row returned by execution of a
SELECT statement
isc_open_blob2() Opens an existing Blob for retrieval, and optionally specifies a filter to
be used to translate the Blob from one subtype to another
isc_put_segment() Writes data into a Blob
TABLE 7.1 API Blob functions
What is a Blob?
A Blob is an object that cannot easily be stored in a database as one of the standard
datatypes. You can use a Blob to store large amounts of data of various types, including:
g Bitmapped images
g Sounds
g Video segments
g Text
118 INTERBASE 6
WHAT IS A BLOB?
InterBase support of Blob data provides all the advantages of a database management
system, including transaction control, maintenance, and access using standard API
function calls. Blob data is stored in the database itself. Other systems only store pointers
in the database to non-database files. InterBase stores the actual Blob data in the
database, and establishes a unique identification handle in the appropriate table to point
to the database location of the Blob. By maintaining the Blob data within the database,
InterBase greatly improves access to and management of the data.
Blob subtypes
Although you manage Blob data in ways similar to other datatypes, InterBase provides
more flexible data typing rules for Blob data. Because there are many native datatypes
that you can define as Blob data, InterBase treats them generically and allows you to
define your own datatype, known as a subtype. InterBase also provides two predefined
subtypes: 0, an unstructured subtype generally applied to binary data or data of an
indeterminate type, and 1, applied to plain text.
User-defined subtypes must always be represented as negative integers between –1 and
–32,678.
A Blob column’s subtype is specified when the Blob column is defined.
The application is responsible for ensuring that data stored in a Blob column agrees with
its subtype; InterBase does not check the type or format of Blob data.
120 INTERBASE 6
BLOB DATA OPERATIONS
2. Allocate memory for the XSQLDA using the XSQLDA_LENGTH macro. The
XSQLDA must contain one XSQLVAR substructure for each column to be
fetched. The following statement allocates storage for an output XSQLDA
(out_sqlda) with three XSQLVAR substructures:
out_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(3));
3. Set the version field of the XSQLDA to SQLDA_VERSION1, and set the sqln field
of the XSQLDA to indicate the number of XSQLVAR substructures allocated:
out_sqlda->version = SQLDA_VERSION1;
out_sqlda->sqln = 3;
122 INTERBASE 6
BLOB DATA OPERATIONS
- Coerce the item’s datatype (optional), for example, from SQL_VARYING to SQL_TEXT.
- Dynamically allocate local storage for the data pointed to by the sqldata field of the
XSQLVAR.
For both:
- Specify the number of bytes of data to be retrieved into sqldata.
- Provide a NULL value indicator for the parameter.
Data retrieval for Blob (and array) columns is different from other types of columns,
so the XSQLVAR fields must be set differently. For non-Blob (and non-array) columns,
isc_dsql_prepare() sets each XSQLVAR sqltype field to the appropriate field type, and
the data retrieved when a select-list row’s data is fetched is placed into the sqldata
space allocated for the column. For Blob columns, the type must be set to SQL_Blob
(or SQL_Blob + 1 if a NULL indicator is desired). InterBase stores the internal Blob
identifier (Blob ID), not the Blob data, in the sqldata space when a row’s data is
fetched, so you must point sqldata to an area the size of a Blob ID. To see how to
retrieve the actual Blob data once you have a Blob ID, see “Reading data from a
Blob” on page 121.
The following code example illustrates the assignments for Blob and non-Blob
columns whose types are known at compile time. For examples of handling datatypes
that are unknown until run time, see Chapter 6, “Working with Dynamic SQL.”
#define PROJLEN 20
#define TYPELEN 12
ISC_QUAD blob_id;
char proj_name[PROJLEN + 1];
char prod_type[TYPELEN + 1];
short flag0, flag1, flag2;
out_sqlda->sqlvar[0].sqldata = proj_name;
out_sqlda->sqlvar[0].sqltype = SQL_TEXT + 1;
out_sqlda->sqlvar[0].sqllen = PROJLEN;
out_sqlda->sqlvar[0].sqlind = &flag0;
out_sqlda->sqlvar[1].sqldata = (char *) &blob_id;
out_sqlda->sqlvar[1].sqltype = SQL_Blob + 1;
out_sqlda->sqlvar[1].sqllen = sizeof(ISC_QUAD);
out_sqlda->sqlvar[1].sqlind = &flag1;
out_sqlda->sqlvar[2].sqldata = prod_type;
out_sqlda->sqlvar[2].sqltype = SQL_TEXT + 1;
out_sqlda->sqlvar[2].sqllen = TYPELEN;
out_sqlda->sqlvar[2].sqlind = &flag2;
124 INTERBASE 6
BLOB DATA OPERATIONS
2. Create a buffer for holding each Blob segment as it is read. Its size should be
the maximum size segment your program expects to be read from the Blob.
char blob_segment[80];
3. Declare an unsigned short variable into which InterBase will store the actual
length of each segment read:
unsigned short actual_seg_len;
126 INTERBASE 6
BLOB DATA OPERATIONS
g Read the old Blob data into a buffer where you can edit or modify it.
g Write the modified data to the new Blob.
g Prepare and execute an UPDATE statement that will modify the Blob column to contain
the Blob ID of the new Blob, replacing the old Blob’s Blob ID.
The sections below describe the steps required to insert, replace, or update Blob data.
The remaining steps refer only to UPDATE statements, but the actions apply to INSERT
statements as well.
2. Declare a variable to hold the input XSQLDA needed to supply parameter
values to the UPDATE statement at run time. For example, the following
declaration creates an XSQLDA called in_sqlda:
XSQLDA *in_sqlda;
3. Allocate memory for the input XSQLDA using the XSQLDA_LENGTH macro. The
XSQLDA must contain one XSQLVAR substructure for each parameter to be
passed to the UPDATE statement. The following statement allocates storage for
an input XSQLDA (in_sqlda) with two XSQLVAR substructures:
in_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(2));
4. Set the version field of the XSQLDA to SQLDA_VERSION1, and set the sqln field
to indicate the number of XSQLVAR structures allocated:
in_sqlda->version = SQLDA_VERSION1;
in_sqlda->sqln = 2;
5. Set up the XSQLVAR structure in the XSQLDA for each parameter to be passed.
Setting up an XSQLVAR structure involves the following steps:
- Specify the item’s datatype
- For parameters whose types are known at compile time: Point the sqldata field of
the XSQLVAR to an appropriate local variable that will contain the data to be passed
- For parameters whose types are not known until run time: Allocate local storage for
the data pointed to by the sqldata field of the XSQLVAR
- Specify the number of bytes of data
Data storage for Blob (and array) columns is different from other types of columns, so
the XSQLVAR fields must be set differently. For non-Blob and non-array columns, input
parameter data comes from the space pointed to by sqldata. For Blob columns, you must
set the type to SQL_Blob (or SQL_Blob + 1 if you want a NULL indicator). Your application
must store space for the internal Blob identifier, not the Blob data, in the sqldata space.
For more information about creating a Blob, storing its ID in the sqldata space, and
associating the Blob with a column, see “Creating a new Blob and storing data” on
page 128.
The following code example illustrates the assignments for one text column and one Blob
column, where the column types are known at compile time. For examples of handling
datatypes that are unknown until run time, see Chapter 6, “Working with Dynamic
SQL.”
#define PROJLEN 5
char proj_id[PROJLEN + 1];
ISC_QUAD blob_id;
in_sqlda->sqlvar[0].sqldata = (char *) &blob_id;
in_sqlda->sqlvar[0].sqltype = SQL_Blob + 1;
in_sqlda->sqlvar[0].sqllen = sizeof(ISC_QUAD);
in_sqlda->sqlvar[1].sqldata = proj_id;
in_sqlda->sqlvar[1].sqltype = SQL_TEXT;
in_sqlda->sqlvar[1].sqllen = 5;
The proj_id variable should be assigned a value at run time (unless the value is
known at compile time). The blob_id variable should be set to refer to the newly
created Blob, as described in the following sections.
128 INTERBASE 6
BLOB DATA OPERATIONS
This function creates a new Blob, opens it for write access, and sets blob_handle to
point to the new Blob.
isc_create_blob2() also assigns the Blob a Blob ID, and sets blob_id to point to the
Blob ID. Note that blob_id is the variable pointed to by the sqldata field of the UPDATE
statement input parameter that specifies the Blob column to be updated. Thus, when
the UPDATE statement is executed, this new Blob will be used to update the Blob
column.
4. Write all the data to be written to the Blob by making a series of calls to
isc_put_segment(). The following example reads lines of data, and
concatenates each to the Blob referenced by blob_handle. (get_line() reads
the next line of data to be written.)
char *line;
unsigned short len;
. . .
line = get_line();
while (line)
{
len = strlen(line);
isc_put_segment(
status_vector,
Deleting a Blob
There are four ways to delete a Blob:
g Delete the row containing the Blob. You can use DSQL to execute a DELETE statement.
g Replace the Blob with a different one. If a Blob column contains a Blob ID, and you
modify the column to refer to a different Blob, the Blob referenced by the previously
stored Blob ID will be deleted during the next garbage collection.
g Reset to NULL the column referring to the Blob, for example, by using DSQL to execute a
statement like the following:
UPDATE PROJECT SET PROJ_DESC = NULL WHERE PROJ_ID = ’VBASE’
130 INTERBASE 6
REQUESTING INFORMATION ABOUT AN OPEN BLOB
The Blob referenced by the previously stored Blob ID will be deleted during the next
garbage collection.
g Discard a Blob after it has been created but before it has been associated with a particular
column of a table row. Use the isc_cancel_blob() function, as in:
isc_cancel_blob(status_vector, &blob_handle);
The result buffer returns a series of clusters of information, one per item requested. Each
cluster consists of three parts:
1. A one-byte item type. Each is the same as one of the item types in the item-list
buffer.
2. A 2-byte number specifying the number of bytes that follow in the remainder
of the cluster.
3. A value, stored in a variable number of bytes, whose interpretation depends
on the item type.
A calling program is responsible for interpreting the contents of the result buffer and for
deciphering each cluster as appropriate.
The clusters returned to the result buffer are not aligned. Furthermore, all numbers are
represented in a generic format, with the least significant byte first, and the most
significant byte last. Signed numbers have the sign in the last byte. Convert the numbers
to a datatype native to your system, if necessary, before interpreting them. The API call,
isc_vax_integer(), can be used to perform the conversion.
The following table lists items about which information can be requested and returned,
and the values reported:
Item Description
isc_info_end End of the messages
isc_info_truncated Result buffer is too small to hold any more requested information
isc_info_error Requested information is unavailable. Check the status vector for an
error code and message
TABLE 7.3 Status message return items
132 INTERBASE 6
REQUESTING INFORMATION ABOUT AN OPEN BLOB
Blob descriptors
A Blob descriptor is used to provide dynamic access to Blob information. For example, it
can be used to store information about Blob data for filtering (conversion) purposes, such
as character set information for text Blob data and subtype information for text and
non-text Blob data. Two Blob descriptors are needed whenever a filter will be used when
writing to or reading from a Blob: one to describe the filter source data, and the other to
describe the target.
A Blob descriptor is a structure defined in the ibase.h header file as follows:
typedef struct {
short blob_desc_subtype; /* type of Blob data */
short blob_desc_charset; /* character set */
short blob_desc_segment_size; /* segment size */
unsigned char blob_desc_field_name [32]; /* Blob column name */
unsigned char blob_desc_relation_name [32]; /* table name */
} ISC_Blob_DESC;
134 INTERBASE 6
POPULATING A BLOB DESCRIPTOR
For more information about the character sets recognized by InterBase, see the Language
Reference.
The segment size of a Blob is the maximum number of bytes that an application is
expected to write to or read from the Blob. You can use this size to allocate your own
buffers.
The blob_desc_relation_name and blob_desc_field_name fields contain null-
terminated strings.
For more information about the usage of Blob descriptors in applications that request
data filtering, and for further examples of populating Blob descriptors, see “Writing an
application that requests filtering” on page 142.
136 INTERBASE 6
FILTERING BLOB DATA
In the example, the filter’s input subtype is defined as –1 and its output subtype as
–2. If subtype –1 specifies lowercase text, and subtype –2 uppercase text, then the
purpose of filter SAMPLE would be to translate Blob data from lowercase text to uppercase
text.
The ENTRY_POINT and MODULE_NAME parameters specify the external routine that
InterBase calls when the filter is invoked. The MODULE_NAME parameter specifies filter.dll,
the dynamic link library containing the filter’s executable code. The ENTRY_POINT
parameter specifies the entry point into the DLL. Although the example shows only a
simple file name, it is good practice to specify a fully-qualified path name, since users of
your application need to load the file.
The parameter, action, is one of eight possible action macro definitions, and the
parameter, control, is an instance of the isc_blob_ctl Blob control structure, defined in
the InterBase header file, ibase.h. These parameters are discussed later in this chapter.
The following listing of a skeleton filter declares the filter function, jpeg_filter:
#include <ibase.h>
#define SUCCESS 0
#define FAILURE 1
ISC_STATUS jpeg_filter(short action, isc_blob_ctl control)
{
ISC_STATUS status = SUCCESS;
switch (action)
{
case isc_blob_filter_open:
. . .
break;
case isc_blob_filter_get_segment:
. . .
break;
case isc_blob_filter_create:
. . .
break;
case isc_blob_filter_put_segment:
. . .
break;
case isc_blob_filter_close:
. . .
break;
case isc_blob_filter_alloc:
. . .
break;
case isc_blob_filter_free:
. . .
break;
case isc_blob_filter_seek:
. . .
break;
default:
. . .
break;
}
138 INTERBASE 6
FILTERING BLOB DATA
return status;
}
InterBase passes one of eight possible actions to the filter function, jpeg_filter, by way of
the action parameter, and also passes an instance of the Blob control structure,
isc_blob_ctl, by way of the parameter, control.
The ellipses (…) in the previous listing represent code that performs some operations
based on each action, or event, that is listed in the case statement. Most of the actions
correspond to API functions called by an application. For more information regarding the
types of code to write for each action, see the Embedded SQL Guide.
The purpose of certain isc_blob_ctl fields depend on the action being performed.
For example, when an application calls the isc_put_segment() API function, InterBase
passes an isc_blob_filter_put_segment action to the filter function. The buffer pointed to
by the ctl_buffer field of the control structure passed to the filter function contains the
segment data to be written, as specified by the application in its call to isc_put_segment().
Because the buffer contains information passed into the filter function, it is called an IN
field. The filter function should include instructions in the case statement under the
isc_blob_filter_put_segment case for performing the filtering and then passing the data
on for writing to the database. This can be done by calling the *ctl_source internal
InterBase Blob access routine. For more information about ctl_source, see the Embedded
SQL Guide.
On the other hand, when an application calls the isc_get_segment() API function, the
buffer pointed to by ctl_buffer in the control structure passed to a filter function is empty.
In this situation, InterBase passes an isc_blob_filter_get_segment action to the filter
function. The filter function isc_blob_filter_get_segment action handling should include
instructions for filling ctl_buffer with segment data from the database to return to the
application. This can be done by calling the *ctl_source internal InterBase Blob access
routine. In this case, because the buffer is used for filter function output, it is called an
OUT field.
The following table describes each of the fields in the isc_blob_ctl Blob control structure,
and whether they are used for filter function input (IN), or output (OUT).
140 INTERBASE 6
FILTERING BLOB DATA
The following table lists the actions, and specifies when the filter function is invoked with
each particular action. Most of the actions are the result of events that occur when an
application invokes a Blob API function.
This concludes the overview of writing Blob filters. For detailed information about filters
and how to program filter function actions, as well as a reference to a filter application
example, see the Embedded SQL Guide.
142 INTERBASE 6
FILTERING BLOB DATA
The BPB is a char array variable, specifically declared in an application, that contains the
source and target subtypes. When data is read from or written to the Blob associated with
the BPB, InterBase will automatically invoke an appropriate filter, based on the source
and target subtypes specified in the BPB.
If the source and target subtypes are both 1 (TEXT), and the BPB also specifies different
source and target character sets, then when data is read from or written to the Blob
associated with the BPB, InterBase will automatically convert each character from the
source to the target character set.
A Blob parameter buffer can be generated in one of two ways:
1. Indirectly, through API calls to create source and target descriptors and then
generate the BPB from the information in the descriptors.
2. Directly by populating the BPB array with appropriate values.
If you generate a BPB via API calls, you do not need to know the format of the BPB. But
if you wish to directly generate a BPB, then you must know the format.
Both approaches are described in the following sections. The format of the BPB is
documented in the section about directly populating the BPB.
For more information about Blob descriptors, see “Blob descriptors” on page 134.
3. Declare a character array which will be used as the BPB. Make sure it is at
least as large as all the information that will be stored in the buffer.
char bpb[20];
4. Declare an unsigned short variable into which InterBase will store the actual
length of the BPB data:
unsigned short actual_bpb_length;
5. Call isc_blob_gen_bpb() to populate the BPB based on the source and target
Blob descriptors passed to isc_blob_gen_bpb(). For example,
isc_blob_gen_bpb(
status_vector,
&to_desc, /* target Blob descriptor */
&from_desc, /* source Blob descriptor */
sizeof(bpb), /* length of BPB buffer */
bpb, /* buffer into which the generated BPB will be stored
*/
&actual_bpb_length /* actual length of generated BPB */
);
144 INTERBASE 6
FILTERING BLOB DATA
The BPB must contain isc_bpb_version1 at the beginning, and must contain clusters
specifying the source and target subtypes. Character set clusters are optional. If the source
and target subtypes are both 1 (TEXT), and the BPB also specifies different source and
target character sets, then when data is read from or written to the Blob associated with
the BPB, InterBase will automatically convert each character from the source to the target
character set.
The following is an example of directly creating a BPB for a filter whose source subtype
is –4 and target subtype is 1 (TEXT):
char bpb[] = {
isc_bpb_version1,
isc_bpb_target_type,
1, /* # bytes that follow which specify target subtype */
1, /* target subtype (TEXT) */
isc_bpb_source_type,
1, /* # bytes that follow which specify source subtype */
–4, /* source subtype*/
};
Of course, if you do not know the source and target subtypes until run time, you can
assign those values in the appropriate BPB locations at run time.
146 INTERBASE 6
FILTERING BLOB DATA
148 INTERBASE 6
CHAPTER
The following table summarizes the API functions for working with arrays. First the
functions that can be used to populate an array descriptor are listed, followed by the
functions for accessing array data.
Function Purpose
isc_array_lookup_desc() Looks up and stores into an array descriptor the datatype, length,
scale, and dimensions for all elements in the specified array column
of the specified table
isc_array_lookup_bounds() Performs the same actions as the function,
isc_array_lookup_desc(), but also looks up and stores the upper
and lower bounds of each dimension
isc_array_set_desc() Initializes an array descriptor from parameters passed to it
isc_array_get_slice() Retrieves data from an array
isc_array_put_slice() Writes data to an array
TABLE 8.1 API array access functions
Introduction to arrays
InterBase supports arrays of most datatypes. Using an array enables multiple data items
to be stored in a single column. InterBase can treat an array as a single unit, or as a series
of separate units, called slices. Using an array is appropriate when:
g The data items naturally form a set of the same datatype.
g The entire set of data items in a single database column must be represented and
controlled as a unit, as opposed to storing each item in a separate column.
g Each item must also be identified and accessed individually.
The data items in an array are called array elements. An array can contain elements of
any InterBase datatype except Blob, and cannot be an array of arrays. All of the elements
of a particular array are of the same datatype.
InterBase supports multi-dimensional arrays, arrays with 1 to 16 dimensions.
Multi-dimensional arrays are stored in row-major order.
Array dimensions have a specific range of upper and lower boundaries, called subscripts.
The array subscripts are defined when an array column is created. For information about
creating an array, see the Language Reference.
150 INTERBASE 6
INTRODUCTION TO ARRAYS
Array descriptors
An array descriptor describes an array or array subset to be retrieved or written to the
ISC_ARRAY_DESC structure. ISC_ARRAY_DESC is defined in the InterBase ibase.h header file as
follows:
typedef struct {
unsigned char array_desc_dtype; /* Datatype */
char array_desc_scale; /* Scale for numeric datatypes */
unsigned short array_desc_length;
/* Length in bytes of each array element */
char array_desc_field_name [32]; /* Column name */
char array_desc_relation_name [32]; /* Table name */
short array_desc_dimensions; /* Number of array dimensions */
short array_desc_flags;
/* Specifies whether array is to be accessed in row-major or
column-major order */
ISC_ARRAY_BOUND array_desc_bounds [16];
/* Lower and upper bounds for each dimension */
} ISC_ARRAY_DESC;
152 INTERBASE 6
ACCESSING ARRAY DATA
154 INTERBASE 6
ACCESSING ARRAY DATA
2. Allocate memory for the XSQLDA using the XSQLDA_LENGTH macro. The
XSQLDA must contain one XSQLVAR substructure for each column to be
fetched. The following statement allocates storage for an output XSQLDA
(out_sqlda) with two XSQLVAR substructures:
out_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(2));
3. Set the version field of the XSQLDA to SQLDA_VERSION1, and set the sqln field
of the XSQLDA to indicate the number of XSQLVAR substructures allocated:
out_sqlda->version = SQLDA_VERSION1;
out_sqlda->sqln = 2;
156 INTERBASE 6
ACCESSING ARRAY DATA
2. Fill in the descriptor with information regarding the array column from
which data will be read. Do this either by calling one of the functions
isc_array_lookup_bounds(), isc_array_lookup_desc(), or
isc_array_set_desc(), or by directly filling in the descriptor. For information
on the contents of array descriptors, and the usage of these functions, see
“Array descriptors” on page 151.
Ensure the descriptor boundaries are set to those of the slice to be read.
If you want to retrieve all the array data (that is, not just a smaller slice), set the
boundaries to the full boundaries as initially declared for the array column. This is
guaranteed to be the case if you fill in the descriptor by calling
isc_array_lookup_bounds(), as in:
ISC_ARRAY_DESC desc;
isc_array_lookup_bounds(
status_vector,
&db_handle,
&trans,
"PROJ_DEPT_BUDGET",/* table name */
"QUART_HEAD_CNT",/* array column name */
&desc);
If you want to read just a slice of the array, then modify the upper and/or lower
bounds appropriately. For example, if you just want to read the first two elements of
the array, then modify the upper bound to the value 2, as in:
desc.array_desc_bounds[0].array_bound_upper = 2
158 INTERBASE 6
ACCESSING ARRAY DATA
1. Create a buffer for holding the array data to be read. Make it large enough to
hold all the elements in the slice to be read (which could be the entire array).
For example, the following declares an array buffer large enough to hold 4
long elements:
long hcnt[4];
2. Declare a short variable for specifying the size of the array buffer:
short len;
4. Read the array or array slice data into the buffer by calling
isc_array_get_slice(). Process the data read. In the following example, the
array is read into the hcnt array buffer, and “processing” consists of printing
the data:
isc_array_get_slice(
status_vector,
&db_handle,/* set by isc_attach_database()*/
&trans, /* set by isc_start_transaction() */
&array_id, /* array ID put into out_sqlda by isc_dsql_fetch()*/
&desc, /* array descriptor specifying slice to be read */
(void *) hcnt,/* buffer into which data will be read */
(long *) &len/* length of buffer */
);
if (status_vector[0] == 1 && status_vector[1])
{
isc_print_status(status_vector);
return(1);
}
/* Make dept_no a null-terminated string */
dept_no[out_sqlda->sqlvar[0].sqllen] = ’\0’;
printf("Department #: %s\n\n", dept_no);
printf("\tCurrent head counts: %ld %ld %ld %ld\n",
hcnt[0], hcnt[1], hcnt[2], hcnt[3]);
160 INTERBASE 6
ACCESSING ARRAY DATA
2. Fill in the descriptor with information regarding the array column to which
data will be written. Do this either by calling one of the functions
isc_array_lookup_bounds(), isc_array_lookup_desc(), or
isc_array_set_desc(), or by directly filling in the descriptor. For information
on the contents of array descriptors, and the usage of these functions, see
“Array descriptors” on page 151.
Ensure the descriptor boundaries are set to those of the slice to be written to.
If you want to write to the entire array rather than to just a slice, set the boundaries
to the full boundaries as initially declared for the array column. This is guaranteed to
be the case if you fill in the descriptor by calling isc_array_lookup_bounds(), as in:
isc_array_lookup_bounds(
status_vector,
db_handle,
&trans,
"PROJ_DEPT_BUDGET",/* table name */
"QUART_HEAD_CNT",/* array column name */
&desc);
Suppose the array column, QUART_HEAD_CNT, is a one-dimensional array consisting of
four elements, and it was declared to have a lower subscript bound of 1 and an upper
bound of 4 when it was created. Then after a call to isc_array_lookup_bounds(), the
array descriptor fields for the boundaries contain the following information:
desc.array_desc_bounds[0].array_bound_lower == 1
desc.array_desc_bounds[0].array_bound_upper == 4
If you just want to write to (or modify) a slice of the array, then change the upper and
lower bound appropriately. For example, if you just want to write to the first two
elements of the array, then modify the upper bound to the value 2, as in:
desc.array_desc_bounds[0].array_bound_upper == 2
If you are creating a new array, then fill the buffer with data. For
example,
hcnt[0] = 4;
hcnt[1] = 5;
hcnt[2] = 6;
hcnt[3] = 6;
To modify existing array data instead of creating a new one, then perform all the steps
listed in “Reading data from an array” on page 154 to read the existing array data
into the array buffer. Modify the data in the buffer.
As an example of an INSERT statement, the following is for inserting a new row into
the PROJ_DEPT_BUDGET table, with column data supplied at run time:
char *upd_str =
"INSERT INTO PROJ_DEPT_BUDGET (YEAR, PROJ_ID, DEPT_NO, \
QUART_HEAD_CNT) VALUES (?, ?, ?, ?)";
The remaining steps refer only to UPDATE statements, but the actions apply to INSERT
statements as well.
2. Declare a variable to hold the input XSQLDA needed to supply parameter
values to the UPDATE statement at run time. For example, the following
declaration creates an XSQLDA called in_sqlda:
XSQLDA *in_sqlda;
162 INTERBASE 6
ACCESSING ARRAY DATA
3. Allocate memory for the input XSQLDA using the XSQLDA_LENGTH macro. The
XSQLDA must contain one XSQLVAR substructure for each parameter to be
passed to the UPDATE statement. The following statement allocates storage for
an input XSQLDA (in_sqlda) with two XSQLVAR substructures:
in_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(2));
4. Set the Version field of the XSQLDA to SQLDA_VERSION1, and set the Sqln field
to indicate the number of XSQLVAR structures allocated:
in_sqlda->version = SQLDA_VERSION1;
in_sqlda->sqln = 2;
5. Set up the XSQLVAR structure in the XSQLDA for each parameter to be passed.
Setting up an XSQLVAR structure involves the following steps:
- Specify the item’s datatype.
- For parameters whose types are known at compile time, point the Ssqldata field of
the XSQLVAR to an appropriate local variable that will contain the data to be passed.
- For parameters whose types are not known until run time, allocate local storage for
the data pointed to by the Sqldata field of the XSQLVAR.
- Specify the number of bytes of data.
Data storage for array (and Blob) columns is different from other types of columns,
so the XSQLVAR fields must be set differently. For non-array (and non-Blob) columns,
input parameter data comes from the space pointed to by Sqldata. For array columns,
set the type to SQL_ARRAY (or SQL_ARRAY + 1 if the array column is allowed to be NULL).
The application must store space for the internal array identifier, not the array data,
in the Sqldata space. See the following sections to create or modify an array, store its
array ID in the Sqldata space, and then associate the actual array data with the
column.
The following code example illustrates the assignments for one TEXT column and one
array column, where the column types are known at compile time.
#define NUMLEN 4
char dept_no[NUMLEN + 1];
ISC_QUAD array_id;
in_sqlda->sqlvar[0].sqldata = &array_id;
in_sqlda->sqlvar[0].sqltype = SQL_ARRAY + 1;
in_sqlda->sqlvar[0].sqllen = sizeof(ISC_QUAD);
in_sqlda->sqlvar[1].sqldata = dept_no;
in_sqlda->sqlvar[1].sqltype = SQL_TEXT;
in_sqlda->sqlvar[1].sqllen = 4;
The dept_no variable should be assigned a value at run time (unless the value is
known at compile time). The array_id variable should be set to refer to the newly
created array, as described in the following sections.
For examples of handling data whose types are not known until run time, see Chapter
6, “Working with Dynamic SQL.”
4 Calling isc_array_put_slice()
The following steps are required to store the data into an array or array slice:
1. Declare an array ID:
ISC_QUAD array_id; /* Declare an array ID. */
2. Initialize the array ID. If you are creating a new array to be inserted into a
new row, or to replace an existing array, then simply initialize the array ID to
NULL:
array_id = NULL;/* Set handle to NULL before using it */
If you are modifying an existing array, then follow the steps listed under “Reading
Data from an Array” to read the existing array ID into array_id.
3. Call isc_array_put_slice(). In your call you pass the array ID (either the array
ID of an existing array, or NULL for a new array) in the array_id variable. You
also pass the buffer of data to be written and a descriptor specifying the array
slice to which the data belongs.
When isc_array_put_slice() is called with an array ID of an existing array, it creates
a new array with the same characteristics as the specified array, and copies the
existing array data to the new array. Then isc_array_put_slice() writes the data from
the array buffer to the new array (or slice of the array), per the bounds specified in
the array descriptor, and returns in the same array_id variable the array ID of the new
array.
When isc_array_put_slice() is called with a NULL array ID, it creates a new empty
array with characteristics as declared for the array column whose name and table
name are specified in the array descriptor passed to isc_array_put_slice(). It then
writes the data from the array buffer to the new array (or slice of the array), and
returns in the array_id variable the array ID of the new array.
Note that in both cases, a new array is created, and its array ID is returned in the
array_id variable. The array is temporary until an UPDATE or INSERT statement is
executed to associate the array with a particular column of a particular row.
164 INTERBASE 6
ACCESSING ARRAY DATA
You can make a single call to isc_array_put_slice() to write all the data to the array.
Or, you may call isc_array_put_slice() multiple times to store data into various slices
of the array. In this case, each call to isc_array_put_slice() after the first call should
pass the array ID of the temporary array. When isc_array_put_slice() is called with
the array ID of a temporary array, it copies the specified data to the specified slice of
the temporary array, but does not create a new array.
The following is a sample call to isc_array_put_slice():
isc_array_put_slice(
status_vector,
&db_handle,
&trans,
&array_id,/* array ID (NULL, or existing array’s array ID) */
&desc, /* array descriptor describing where to write data */
hcnt, /* array buffer containing data to write to array */
&len /* length of array buffer */
);
This call creates a new array, copies the data in hcnt to the new array (or slice of the
array), assigns the array an array ID, and sets array_id to point to the array ID.
IMPORTANT array_id should be the variable pointed to by the Sqldata field of the UPDATE (or INSERT)
statement input parameter that specifies the array column to be updated. Thus, when
the INSERT or UPDATE statement is executed, this new array’s array ID will be used to set
or update the array column to refer to the new array.
This sets the array column in the row specified in the UPDATE statement to contain the
array ID of the new array. The array ID comes from the array_id variable pointed to by
the in_sqlda parameter corresponding to the array column.
If the array column in the specified row contains the array ID of a different array before
the UPDATE statement is executed, then the column is modified to contain the new array
ID, and the array referenced by the previously stored array ID will be deleted during the
next garbage collection.
Deleting an array
There are three ways to delete an array:
1. Delete the row containing the array. You can use DSQL to execute a DELETE
statement.
2. Replace the array with a different one, as described above. If an array column
contains an array ID, and you modify the column to refer to a different array,
the array referenced by the previously stored array ID will be deleted during
the next garbage collection.
3. Reset to NULL the column referring to the array. For example, use DSQL to
execute a statement like the following, where LANGUAGE_REQ is an array
column:
"UPDATE JOB SET LANGUAGE_REQ = NULL \
WHERE JOB_CODE = "SA12" AND JOB_GRADE = 10"
The array referenced by the previously stored array ID will be deleted during the next
garbage collection.
166 INTERBASE 6
CHAPTER
Note In InterBase 6, the DATE datatype holds only date information in dialect 3 and is
not permitted in dialect 1 to avoid ambiguity. When an older database is migrated to
version 6 dialect 1, all columns that previously had a DATE datatype are automatically
converted to TIMESTAMP. To store migrated data in a DATE column in dialect 3, you must
create a new column in dialect 3 that has the DATE datatype, and then move the data into
it. InterBase does not allow you to use ALTER COLUMN to change a TIMESTAMP datatype to
a DATE datatype because of potential data loss.
InterBase also requires that numbers entered in database and transaction parameter
buffers be in a generic format, with the least significant byte last. Signed numbers require
the sign to be in the last byte. Systems that represent numbers with the most significant
byte last must use the isc_vax_integer() API function to reverse the byte order of numbers
entered in database parameter buffers (DPBs) and transaction parameter buffers (TPBs).
When numeric information is returned by information calls on these systems,
isc_vax_integer() must be used once again to reverse the byte ordering.
For more information about using DSQL to read and write data, see Chapter 6, “Working
with Dynamic SQL.”
Note To create host-language time structures in languages other than C and C++, see the
host-language reference manual.
168 INTERBASE 6
CONVERTING DATES FROM C TO INTERBASE FORMAT
The ISC_TIMESTAMP structure is declared in ibase.h, but the programmer must declare
actual host-language variables of type ISC_TIMESTAMP.
3. Retrieve a date from a table into the ISC_TIMESTAMP variable.
4. Convert the ISC_TIMESTAMP variable into a numeric C format with the
InterBase function, isc_sql_decode_timestamp(). This function is also
declared in ibase.h. isc_sql_decode_timestamp() requires two parameters, the
address of the ISC_TIMESTAMP host-language variable, and the address of the
struct tm host-language variable. For example, the following code fragment
coverts entry_date to entry_time:
isc_decode_timestamp(&entry_date, &entry_time);
To create host-language time structures in languages other than C and C++, see the
host-language reference manual.
2. Create a host variable of type ISC_TIMESTAMP, for use by InterBase. For
example, the host-variable declaration might look like this:
ISC_TIMESTAMP mytime;
The ISC_TIMESTAMP structure is declared in ibase.h, but the programmer must declare
actual host-language variables of type ISC_TIMESTAMP.
buffer is a char pointer to the integer to convert, and length is the size, in bytes, of the
integer. Valid lengths are 1 (short), 2 (int), and 4(long). The following code reverses the
4-byte value in a result buffer.
#include <ibase.h>
. . .
for(p = res_buffer; *p != isc_info_end;)
{
p++;
length = isc_vax_integer(p, 2);
}
170 INTERBASE 6
CHAPTER
Function Purpose
isc_interprete() Capture InterBase error messages to a buffer
isc_print_sqlerror() Display an SQL error message
isc_print_status() Display InterBase error messages
isc_sqlcode() Set the value of SQLCODE
isc_sql_interprete() Capture an SQL error message to a buffer
TABLE 10.1 Error-handling functions
172 INTERBASE 6
USING INFORMATION IN THE STATUS VECTOR
To check the status vector for error conditions after the execution of a function, examine
the first element of the status vector to see if it is set to 1, and if so, examine the second
element to see if it is not 0. A nonzero value in the second element indicates an error
condition. The following C code fragment illustrates how to check the status vector for
an error condition:
#include <ibase.h>
. . .
ISC_STATUS status_vector[20];
. . .
/* Assume an API call returning status information is called here. */
if (status_vector[0] == 1 && status_vector[1] > 0)
{
/* Handle error condition here. */
;
}
If an error condition is detected, you can use API functions in an error-handling routine
to display error messages, capture the error messages in a buffer, or parse the status
vector for particular error codes.
Display or capture of error messages is only one part of an error-handling routine.
Usually, these routines also roll back transactions, and sometimes they can retry failed
operations.
. . .
ISC_STATUS status_vector[20];
isc_tr_handle trans;
. . .
trans = 0L;
. . .
/* Assume a transaction, trans, is started here. */
/* Assume an API call returning status information is called here. */
if (status_vector[0] == 1 && status_vector[1] > 0)
{
isc_print_status(status_vector);
isc_rollback_transaction(status_vector, &trans);
}
IMPORTANT On windowing systems that do not permit direct screen writes with printf(), use
isc_interprete() to capture error messages to a buffer.
Tip For applications that use the dynamic SQL (DSQL) API functions, errors should be
displayed using SQL conventions. Use isc_sqlcode() and isc_print_sqlerror() instead of
isc_print_status().
174 INTERBASE 6
USING INFORMATION IN THE STATUS VECTOR
Given both the location of a buffer, and the address of the status vector, isc_interprete()
builds an error message from the information in the status vector, puts the formatted
string in the buffer where an application can manipulate it, and advances the status
vector pointer to the start of the next cluster of error information. isc_interprete()
requires two parameters, the address of an application buffer to hold formatted message
output, and a pointer to the status vector array.
IMPORTANT Never pass the status vector array directly to isc_interprete(). Each time it is called,
isc_interprete() advances the pointer to the status vector to the next element containing
new message information. Before calling isc_interprete(), be sure to set the pointer to
the starting address of the status vector.
The following code demonstrates an error-handling routine that makes repeated calls to
isc_interprete() to retrieve error messages from the status vector in a buffer, one at a time,
so they can be written to a log file:
#include <ibase.h>
. . .
ISC_STATUS status_vector[20];
isc_tr_handle trans;
long *pvector;
char msg[512];
FILE *efile; /* Code fragment assumes pointer to an open file. */
trans = 0L;
. . .
/* Error-handling routine starts here. */
/* Always set pvector to point to start of status_vector. */
pvector = status_vector;
/* Retrieve first message. */
isc_interprete(msg, &pvector);
/* Write first message from buffer to log file. */
fprintf(efile, "%s\n", msg);
msg[0] = ’-’; /* Append leading hyphen to secondary messages. */
/* Look for more messages and handle in a loop. */
while(isc_interprete(msg + 1, &pvector)) /* More? */
fprintf(efile, "%s\n", msg); /* If so, write it to the log. */
fclose(efile); /* All done, so close the log file. */
isc_rollback(status_vector, &trans);
return(1);
. . .
Note This code fragment assumes that the log file is properly declared and opened
elsewhere in the application before control is passed to this error handler.
Tip For applications that use the dynamic SQL (DSQL) API functions, errors should be
buffered using SQL conventions. Use isc_sqlcode() and isc_sql_interprete() instead of
isc_interprete().
If successful, isc_sqlcode() returns the first valid SQL error code decoded from the status
vector. If no valid SQL error code is found, isc_sqlcode() returns –999.
176 INTERBASE 6
USING INFORMATION IN THE STATUS VECTOR
#include <ibase.h>
. . .
ISC_STATUS status_vector[20];
isc_tr_handle trans;
long SQLCODE;
. . .
trans = 0L;
. . .
/* Assume a transaction, trans, is started here. */
/* Assume an API call returning status information is called here. */
if (status_vector[0] == 1 && status_vector[1] > 0)
{
SQLCODE = isc_sqlcode(status_vector);
isc_print_sqlerror(SQLCODE, status_vector);
isc_rollback_transaction(status_vector, &trans);
}
IMPORTANT On windowing systems that do not permit direct screen writes with printf(), use
isc_sql_interprete() to capture error messages to a buffer.
Note This code fragment assumes that the log file is properly declared and opened
elsewhere in the application before control is passed to this error handler.
178 INTERBASE 6
USING INFORMATION IN THE STATUS VECTOR
By including ibase.h at the start of your source code, you can use a series of #defines to
substitute for hard-coded numeric descriptors in the status vector parsing routines you
write. The advantages of using these #defines over hard-coding the descriptors are:
g Your code will be easier to read.
g Code maintenance will be easier should the numbering scheme for numeric descriptors
change in a future release of InterBase.
The following table lists the #define equivalents of each numeric descriptor:
180 INTERBASE 6
USING INFORMATION IN THE STATUS VECTOR
For an example of code that uses these defines, see “Status vector parsing example”
on page 183.
STRING ADDRESSES
String addresses point to error message text. When the first long in the cluster is 2
(isc_arg_string), the address pointed to often contains the name of the database, table,
or column affected by the error. In these cases, InterBase functions which build error
message strings replace a parameter in a generic InterBase error message with the string
pointed to by this address. Other times the address points to an error message hard-coded
in a database trigger.
When the first long in the cluster is 5 (isc_arg_interpreted), the address points to a text
message which requires no further processing before retrieval. Sometimes this message
may be hard-coded in InterBase itself, and other times it may be a system-level error
message.
In either of these cases, InterBase functions such as isc_print_status() and
isc_interprete() can format and display the resulting error message for you.
NUMERIC VALUES
A numeric value has different meaning depending upon the value of the numeric
descriptor in the first long of a cluster. If the first long is 4 (isc_arg_number), a numeric
value is used by InterBase functions to replace numeric parameters in generic InterBase
error messages during message building. For instance, when an integrity error occurs,
InterBase stores the code of the trigger which detects the problem as a numeric value in
the status vector. When an InterBase function like isc_interprete() builds the error
message string for this error, it inserts the numeric value from the status vector into the
generic InterBase integrity error message string to make it more specific.
182 INTERBASE 6
USING INFORMATION IN THE STATUS VECTOR
printf("%s\n", meaning[2]);
break;
case gds_arg_number:
printf("%s\n", meaning[4]);
break;
case gds_arg_cstring:
printf("%s\n", meaning[3]);
extra = 1;
break;
default:
printf("%s\n", meaning[5]);
break;
}
if (!done)
{
printf("Status vector %d: %ld", v, status_vector[v]);
v++;/* advance vector pointer */
c++;/* advance cluster count */
if (extra)
{
printf(": Next long is a %s\n", meaning[2]);
printf("Status vector: %d: %ld\n\n", v,
status_vector[v]);
v++;
}
else
printf("\n\n");
}
}
isc_rollback_transaction(status_vector, &trans);
isc_detach_database(&db1);
return(1);
}
184 INTERBASE 6
USING INFORMATION IN THE STATUS VECTOR
This output indicates that two InterBase errors occurred. The first error code is
335544342. The error printing routines, isc_print_status() and isc_interprete(), use the
InterBase error code to retrieve a corresponding base error message. The base error
message contains placeholders for replaceable parameters. For error code 335544342, the
base error message string is:
"action cancelled by trigger (%ld) to preserve data integrity"
The second error code is 335544382. The base message retrieved for this error code is:
"%s"
In this case, the entire message to be displayed consists of a replaceable string. The
second long of the fourth cluster contains the address of the replacement string, 156740.
This is an error message defined in the trigger that caused the error. When the error
printing routine inserts the message from the trigger into the base message, it displays
the resulting message:
-Department name is missing.
Note This sample program is only meant to illustrate the structure of the status vector
and its contents. While the error-handling routine in this program might serve as a limited
debugging tool for a program under development, it does not provide useful information
for end users. Ordinarily, error-handling blocks in applications should interpret errors,
display explanatory error messages, and take corrective action, if appropriate.
For example, if the error-handling routine in the sample program had called
isc_print_status() to display the error messages associated with these codes, the
following messages would have been displayed:
action cancelled by trigger (1) to preserve data integrity
-Department name is missing.
186 INTERBASE 6
CHAPTER
Function Purpose
isc_event_block() Allocate event parameter buffers
isc_wait_for_event() Wait for a synchronous event to be posted
isc_que_events() Set up an asynchronous event and return to application processing
isc_event_counts() Determine the change in values of event counters in the event parameter
buffer
isc_cancel_events() Cancel interest in an event
TABLE 11.1 API event functions
For asynchronous events, this chapter also describes how to create an asynchronous trap
(AST), a function that responds to posted events.
188 INTERBASE 6
UNDERSTANDING THE EVENT MECHANISM
This code assumes that there are triggers or stored procedures defined for the database
that post events named “BORL”, “INTEL”, and “SUN”.
Tip Applications that need to respond to more than 15 events can make multiple calls to
isc_event_block(), specifying different EPBs and event lists for each call.
For the complete syntax of isc_event_block(), see “isc_event_block()” on page 347.
190 INTERBASE 6
WAITING ON EVENTS WITH isc_wait_for_event( )
For example, the following code sets up EPBs for three events, then calls
isc_wait_for_event() to suspend its execution until one of the events occurs:
#include <ibase.h>;
. . .
char *event_buffer, *result_buffer;
long blength;
ISC_STATUS status_vector[20];
isc_db_handle db1;
. . .
/* Assume database db1 is attached here and a transaction started. */
blength = isc_event_block(&event_buffer, &result_buffer, 3, "BORL",
"INTEL", "SUN");
isc_wait_for_event(status_vector, &db1, (short)blength,
event_buffer, result_buffer);
/* Application processing is suspended here until an event occurs. */
. . .
Once isc_wait_for_event() is called, application processing stops until one of the
requested events is posted. When the event occurs, application processing resumes at the
next executable statement following the call to isc_wait_for_event(). If an application is
waiting on more than one event, it must use isc_event_counts() to determine which event
was posted.
192 INTERBASE 6
CONTINUOUS PROCESSING WITH isc_que_events( )
Creating an AST
The event function, event_function, should be written to take three arguments:
1. The event_function_arg specified in the call to isc_que_events(). This is
usually a pointer to the event parameter buffer that should be filled in with
updated event counts.
2. The length of the following events_list buffer.
3. A pointer to the events_list buffer, a temporary event parameter buffer just
like that passed to isc_que_events(), except for having updated event counts.
A result buffer is not automatically updated by the event occurrence; it is up to the
event_function to copy the temporary events_list buffer to the more permanent buffer
that the application utilizes.
event_function also needs to let the application know that it has been called, for
example, by setting a global flag.
A sample event_function appears in the following example:
isc_callback event_function
(char *result, short length, char *updated)
{
/* Set the global event flag. */
event_flag++
/* Copy the temporary updated buffer to the result buffer. */
while (length--)
*result++ = *updated++;
return(0);
};
194 INTERBASE 6
CONTINUOUS PROCESSING WITH isc_que_events( )
For example, the following code declares interest in three events, waits on them, then
uses isc_event_counts() to determine which events occurred:
#include <ibase.h>;
. . .
char *event_buffer, *result_buffer;
long blength;
ISC_STATUS status_vector[20];
isc_db_handle db1;
long count_array[3];
int i;
196 INTERBASE 6
CANCELING INTEREST IN ASYNCHRONOUS EVENTS WITH isc_cancel_events( )
. . .
/* Assume database db1 is attached here and a transaction started. */
blength = isc_event_block(&event_buffer, &result_buffer, 3, "BORL",
"INTEL", "SUN");
isc_wait_for_event(status_vector, &db1, (short)blength,
event_buffer, result_buffer);
/* Application processing is suspended here until an event occurs. */
isc_event_counts(status_vector, (short)blength, event_buffer,
result_buffer);
for (i = 0; i < 3; i++)
{
if (status_vector[i])
{
/* Process the event here. */
;
}
}
event_id is an event handle set in a previous call to isc_que_events(). For example, the
following code cancels interest in the event or events identified by event_id:
include <ibase.h>;
. . .
/* For example code leading up to this call, see the code example
in "Continuous Processing with isc_event_que(), earlier in this
chapter. */
isc_cancel_events(status_vector, &db_handle, &event_id);
General information
The Services API is a group of functions in the InterBase client library (gds32.dll on
Windows, libgds.a on UNIX/Linux). The features that you can exercise with the
Services API include those of the command-line tools gbak, gfix, gsec, gstat, and iblicense
(see the Operations Guide for information on these tools). The Services API can also
perform other functions that are not provided by these tools.
All InterBase servers include a facility called the Services Manager. The Services API
enables client applications to submit requests to the Services Manager of an InterBase
server, and the Services Manager performs the tasks. The server can be local (on the same
host as your application), or remote (on another host on the network). The Services API
offers the same features when connected to either local or remote InterBase servers.
The Services API family consists of the following four functions:
g isc_service_attach( ) initiates a connection to a specified Services Manager
g isc_service_start( ) invokes a service task
g isc_service_query( ) requests information or task results from the Services Manager
g isc_service_detach( ) disconnects from the Services Manager
For full details on the syntax and options of the Services API functions, see the reference
entries for “isc_service_attach( )” on page 376, “isc_service_detach( )” on page 377,
“isc_service_query( )” on page 378, and “isc_service_start( )” on page 380.
200 INTERBASE 6
OVERVIEW OF THE SERVICES API
An SPB is a char array variable that you declare in your application. It contains the
following elements:
1. A byte that introduces the version of the SPB format, always the compile-time
constant, isc_spb_version.
2. A byte that specifies the version number. InterBase supplies a macro
isc_spb_current_version, that is defined as the recommended SPB version
for each given release of the InterBase product.
3. A contiguous series of one or more clusters of bytes follow, each describing
a single argument.
Each cluster consists of the following parts:
1. A byte that introduces the parameter type for each cluster. There are
compile-time constants defined for all the parameter types (for example,
isc_spb_user_name).
2. A byte that specifies the number of bytes that follow in the remainder of the
cluster argument; this is not needed for certain parameter types that have
fixed-length arguments.
3. A variable number of bytes that contain data, depending on the parameter
type.
Subsequent clusters follow immediately in the SPB array.
For example, the following C/C++ code fills an SPB buffer with the SPB version and a
cluster for the user name.
EXAMPLE 12.1 Filling a services parameter buffer in C/C++
Line 1 declares an array of 128 bytes, and a pointer initialized to the first entry in the
array.
Line 2 assigns the item specifier for the SPB version to the first element of the array. Every
SPB must have this item at the start of the array. Since this SPB item is always one byte
long, it doesn’t take a length specifier.
Line 3 assigns the value for the SPB version item.
Line 4 assigns the cluster identifier for the user name string to the next element of the
array.
Line 5 provides the length of the following string. In this example, the string is “SYSDBA”,
and the length is 6.
Line 6 copies the string “SYSDBA” into the array starting at the current element.
Line 7 increments the SPB pointer past the string “SYSDBA”, positioning it for additional
clusters.
IMPORTANT All numbers in the database parameter buffer must be represented in a generic format,
with the least significant byte first. Signed numbers should have the sign in the last byte.
The API function isc_vax_integer() can be used to reverse the byte order of a number.
For more information, see “isc_vax_integer()” on page 391.
Replace serverhost with the hostname of your InterBase database server. In all cases, the
string service_mgr is a literal string.
The user ID you use to attach to the Services Manager is the user ID the Services Manager
uses to perform tasks by your request. Note that some service tasks can be performed
only by the SYSDBA user ID.
202 INTERBASE 6
OVERVIEW OF THE SERVICES API
*spb++ = isc_spb_version;
*spb++ = isc_spb_current_version;
*spb++ = isc_spb_user_name;
*spb++ = strlen(user);
strcpy(spb, user);
spb += strlen(user);
*spb++ = isc_spb_password;
*spb++ = strlen(password)
strcpy(spb, password);
spb += strlen(password);
if (isc_service_attach(status, 0, service_name,
&service_handle, spb_length, spb_buffer))
{
isc_print_status(status);
exit(1);
}
isc_service_detach(status, &service_handle);
204 INTERBASE 6
INVOKING SERVICE TASKS WITH isc_service_start( )
See the following sections for descriptions of tasks and examples of starting them.
Argument Argument
Argument Purpose length value
isc_spb_dbname Path of the primary file of the database, from the 2-byte length String
server’s point of view + string
isc_spb_verbose If specified, the Services Manager prepares — —
output to return via isc_service_query();
corresponds to gbak -verbose
isc_spb_bkp_file Path of a backup output file; you can specify 2-byte length String
multiple output files; corresponds to gsplit + string
functionality
isc_spb_bkp_length Length in bytes of the backup output file; you 2-byte length String
must specify one length value for each output file + string
except the last; corresponds to gsplit
functionality
isc_spb_bkp_factor Tape device blocking factor; corresponds to gbak 4 bytes Unsigned long
-factor
isc_spb_options The following value is a bitmask of 4 bytes Bitmask
isc_spb_bkp_xxxx options below
isc_spb_bkp_ignore_checksums Ignore checksums during backup; corresponds to — Bit
gbak -ignore
isc_spb_bkp_ignore_limbo Ignore limbo transactions during backup; — Bit
corresponds to gbak -limbo
isc_spb_bkp_metadata_only Output backup file for metadata only with empty — Bit
tables; corresponds to gbak -metadata
isc_spb_bkp_no_garbage_collect Suppress normal garbage collection during — Bit
backup; improves performance on some
databases; corresponds to gbak -garbage_collect
TABLE 12.3 Services API database backup arguments
206 INTERBASE 6
INVOKING SERVICE TASKS WITH isc_service_start( )
Argument Argument
Argument Purpose length value
isc_spb_bkp_old_descriptions Output metadata in pre-4.0 format; corresponds — Bit
to gbak -old_descriptions
isc_spb_bkp_non_transportable Output backup file format with non-XDR data — Bit
format; improves space and performance by a
negligible amount; corresponds to gbak -nt
isc_spb_bkp_convert Convert external table data to internal tables; — Bit
corresponds to gbak -convert
TABLE 12.3 Services API database backup arguments
/* Identify cluster */
*p++ = isc_action_svc_backup;
if (isc_service_start(status,
&service_handle,
NULL,
p - request,
request))
{
isc_print_status(status);
isc_service_detach(status, service_handle);
exit(1);
}
You can also restore database backup files to create a new .gdb file. The following table
lists arguments to the cluster identifier isc_action_svc_restore:
Argument Argument
Argument Purpose length value
isc_spb_bkp_file The path of the backup file name 2-byte length String
+ string
isc_spb_dbname Path of the primary file of the database, from the 2-byte length String
server’s point of view; you can specify multiple + string
database files
isc_spb_res_length The length in pages of the restored database file; 4 bytes Unsigned long;
must not exceed 2 gigabytes; you must supply a pages in
length for each database file except the last database file
isc_spb_verbose If specified, the Services Manager prepares — —
output to return via isc_service_query();
corresponds to gbak -verbose
isc_spb_res_buffers The number of default cache buffers to configure 4 bytes Unsigned long;
for attachments to the restored database; number of
corresponds to gbak -buffers buffers
isc_spb_res_page_size The page size for the restored database;
corresponds to gbak -page_size
TABLE 12.4 Services API database restore arguments
208 INTERBASE 6
INVOKING SERVICE TASKS WITH isc_service_start( )
Argument Argument
Argument Purpose length value
isc_spb_res_access_mode Set the access mode of the database; the next 1 byte Byte
byte must be one of:
• isc_spb_prp_am_readonly
• isc_spb_prp_am_readwrite
Corresponds to gbak -mode
isc_spb_options The following value is a bitmask of 4 bytes Bitmask
isc_spb_res_xxxx options below
isc_spb_res_deactivate_idx Do not build user indexes during restore; — Bit
corresponds to gbak -inactive
isc_spb_res_no_shadow Do not recreate shadow files during restore; — Bit
corresponds to gbak -kill
isc_spb_res_no_validity Do not enforce validity conditions (for example, — Bit
NOT NULL) during restore; corresponds to gbak
-no_validity
isc_spb_res_one_at_a_time Commit after completing restore of each table; — Bit
corresponds to gbak -one_at_a_time
isc_spb_res_replace Replace database, if one exists; corresponds to — Bit
gbak -replace
isc_spb_res_create Restore but do not overwrite an existing — Bit
database; corresponds to gbak -create
isc_spb_res_use_all_space Do not reserve 20% of each data page for future — Bit
record versions; useful for read-only databases;
corresponds to gbak -use_all_space
TABLE 12.4 Services API database restore arguments
/* Identify cluster */
*p++ = isc_action_svc_restore;
if (isc_service_start(status,
&service_handle,
NULL,
p - request,
request))
{
isc_print_status(status);
isc_service_detach(status, service_handle);
exit(1);
}
210 INTERBASE 6
INVOKING SERVICE TASKS WITH isc_service_start( )
Argument Argument
Argument Purpose length value
isc_spb_dbname Path of the primary file of the database, from 2-byte length String
the server’s point of view + string
isc_spb_prp_page_buffers Set the default number of cache buffers to the 4 bytes Unsigned long
specified number; corresponds to gfix -buffers
isc_spb_prp_sweep_interval Set the sweep interval to the specified 4 bytes Unsigned long
number; specify zero to disable sweeping;
corresponds to gfix -housekeeping
isc_spb_prp_shutdown_db Shuts down the database when: 4 bytes Unsigned long
• There are no connections to the database, or
• At the end of the timeout period you specify
Corresponds to gfix -shut -force n
isc_spb_prp_deny_new_transactions Shuts down the database if there are no active 4 bytes Unsigned long
transactions at the end of the timeout period
you specify; deny new transactions during this
timeout period; fail if there are active
transactions at the end of the timeout period;
corresponds to gfix -shut -tran n
isc_spb_prp_deny_new_attachments Shuts down the database if there are no active 4 bytes Unsigned long
transactions at the end of the timeout period
you specify; deny new database attachments
during this timeout period; fail if there are
active database attachments at the end of the
timeout period; corresponds to
gfix -shut -attach n
TABLE 12.5 Services API database properties arguments
Argument Argument
Argument Purpose length value
isc_spb_prp_reserve_space Configure the database to fill data pages when 1 byte Byte
inserting new records, or reserve 20% of each
page for later record deltas; the next byte must
be one of:
• isc_spb_prp_res_use_full
• isc_spb_prp_res
Corresponds to gfix -use
isc_spb_prp_write_mode Set the write mode for the database; the next 1 byte Byte
byte must be one of:
• isc_spb_prp_wm_async
• isc_spb_prp_wm_sync
Corresponds to gfix -write
isc_spb_prp_access_mode Set the access mode of the database; the next 1 byte Byte
byte must be one of:
• isc_spb_prp_am_readonly
• isc_spb_prp_am_readwrite
Corresponds to gfix -mode
isc_spb_prp_set_sql_dialect Set the SQL dialect for the database; value 4 bytes Unsigned long
must be either 1 or 3
isc_spb_options The following value is a bitmask of 4 bytes Bitmask
isc_spb_prp_xxxx options below
isc_spb_prp_activate Activate shadow file for use as a database; — Bit
corresponds to gfix -activate
isc_spb_prp_db_online Bring a shutdown database back online; — Bit
corresponds to gfix -online
TABLE 12.5 Services API database properties arguments
212 INTERBASE 6
INVOKING SERVICE TASKS WITH isc_service_start( )
IMPORTANT The validation operation cannot guarantee to repair all cases of corruption. Do not rely
on database validation as a disaster recovery policy in lieu of making regular backups of
your database.
The following table lists arguments to isc_action_svc_repair to validate a database:
Argument Argument
Argument Purpose length value
isc_spb_dbname Path of the primary file of the database, from the 2-byte length String
server’s point of view + string
isc_spb_options The following value is a bitmask of 4 bytes Bitmask
isc_spb_rpr_xxxx options below
isc_spb_rpr_check_db Request read-only validation of the database, — Bit
without correcting any problems; corresponds to
gfix -no_update
isc_spb_rpr_ignore_checksum Ignore all checksum errors; corresponds to gfix — Bit
-ignore
isc_spb_rpr_kill_shadows Remove references to unavailable shadow files; — Bit
corresponds to gfix -kill
isc_spb_rpr_mend_db Mark corrupted records as unavailable, so — Bit
subsequent operations skip them; corresponds
to gfix -mend
TABLE 12.6 Services API database validation arguments
Argument Argument
Argument Purpose length value
isc_spb_rpr_validate_db Locate and release pages that are allocated but — Bit
unassigned to any data structures; corresponds
to gfix -validate
isc_spb_rpr_full Check record and page structures, releasing — Bit
unassigned record fragments; use with
isc_spb_rpr_validate_db; corresponds to gfix
-full
TABLE 12.6 Services API database validation arguments
Argument Argument
Argument Purpose length value
isc_spb_dbname Path of the primary file of the database, from the 2-byte length String
server’s point of view + string
isc_spb_options The following value is a bitmask of 4 bytes Bitmask
isc_spb_rpr_xxxx options below
isc_spb_rpr_sweep_db Request database sweep to mark outdated — Bit
records as free space; corresponds to gfix -sweep
TABLE 12.7 Services API database sweep arguments
214 INTERBASE 6
INVOKING SERVICE TASKS WITH isc_service_start( )
Argument Argument
Argument Purpose length value
isc_spb_dbname Path of the primary file of the database, from the 2-byte length String
server’s point of view + string
isc_spb_rpr_commit_trans Request that the Services Manager commit the — —
transactions that follow
isc_spb_rpr_rollback_trans Request that the Services Manager roll back the — —
transactions that follow
isc_spb_rpr_recover_two_phase Request that the Services Manager use — —
automatic two-phase commit recovery on the
specified transactions
isc_spb_tra_id Precedes a transaction ID number 4 bytes Unsigned long
TABLE 12.8 Services API limbo transaction arguments
Argument Argument
Argument Purpose length value
isc_spb_dbname Path of the primary file of the database, from the 2-byte length String
server’s point of view + string
isc_spb_options The following value is a bitmask of 4 bytes Bitmask
isc_spb_sts_xxxx options below
isc_spb_sts_data_pages Request statistics for user data pages; — Bit
corresponds to gstat -data
isc_spb_sts_db_log Request only the information in the database log — Bit
pages; corresponds to gstat -log
isc_spb_sts_hdr_pages Request only the information in the database — Bit
header page; corresponds to gstat -header
isc_spb_sts_idx_pages Request statistics for user index pages; — Bit
corresponds to gstat -index
isc_spb_sts_sys_relations Request statistics for system tables and indexes — Bit
in addition to user tables and indexes;
corresponds to gstat -system
TABLE 12.9 Services API status report arguments
216 INTERBASE 6
INVOKING SERVICE TASKS WITH isc_service_start( )
Configuring users
You can use the Services API to display, add, delete, and modify users. This corresponds
to the functionality of the command-line tool gsec.
Argument Argument
Argument Purpose length value
isc_spb_sec_username Specify a single user by name for which the 2 byte length String
Services Manager should return information + string
TABLE 12.10 Services API display users arguments
To request the Services Manager to return information for all users in isc4.gdb, omit the
isc_spb_sec_username argument.
You can retrieve the information that the server manager returns by using
isc_service_query() with the cluster identifier isc_info_svc_get_users. See “Querying
using Services API: server configuration information” on page 229.
Argument Argument
Argument Purpose length value
isc_spb_sec_username User name to create in isc4.gdb; maximum 31 2 byte length String
characters; mandatory argument + string
isc_spb_sec_password Password for the user; maximum 31 characters, 2 byte length String
only first 8 characters are significant; mandatory + string
argument
isc_spb_sec_firstname Optional first name of the person using this user 2 byte length String
name + string
isc_spb_sec_middlename Optional middle name of the person using this 2 byte length String
user name + string
TABLE 12.11 Services API add user arguments
Argument Argument
Argument Purpose length value
isc_spb_sec_lastname Optional last name of the person using this user 2 byte length String
name + string
isc_spb_sec_userid Optional user ID number, defined in /etc/passwd, 4 bytes Unsigned long
to assign to the user in isc4.gdb; reserved for
future implementation
isc_spb_sec_groupid Optional group ID number, defined in /etc/group, 4 bytes Unsigned long
to assign to the user in isc4.gdb; reserved for
future implementation
isc_spb_sec_groupname Optional group name, as defined in /etc/group, to 2 byte length String
assign to the user in isc4.gdb; reserved for future + string
implementation
isc_spb_sql_role_name Optional SQL role to adopt when administering 2 byte length String
users (reserved for future use) + string
TABLE 12.11 Services API add user arguments
Argument Argument
Argument Purpose length value
isc_spb_sec_username Name of user to delete from isc4.gdb; mandatory 2 byte length String
argument + string
isc_spb_sql_role_name Optional SQL role to adopt when administering 2 byte length String
users (reserved for future use) + string
TABLE 12.12 Services API remove user arguments
If you remove a user entry from isc4.gdb, no one can log in to any database on that server
using that name. You must create a new entry for that name using
isc_action_svc_add_user.
218 INTERBASE 6
INVOKING SERVICE TASKS WITH isc_service_start( )
Argument Argument
Argument Purpose length value
isc_spb_lic_key The key string identifying a software activation 2 byte length String
certificate + string
isc_spb_lic_id The ID string for a software activation certificate 2 byte length String
(isc_action_svc_add_license only) + string
TABLE 12.13 Services API software activation certificate arguments
See “Querying using Services API: software activation certificates” on page 227 for
an example of retrieving the certificate information with isc_service_query().
220 INTERBASE 6
QUERYING THE SERVICES MANAGER
You can supply to isc_service_query() an SPB item specifying a finite duration after
which the call to isc_service_query() must return, even if output from the task is not yet
available. Populate the SPB with the SPB version information, followed by the
isc_info_svc_timeout cluster identifier, and a four-byte value specifying the number of
seconds for the timeout.
This is the only useful SPB cluster for isc_service_query() in the current implementation.
*spb++ = isc_info_svc_timeout;
ADD_SPB_NUMERIC(spb, 60); /* 1 minute timeout */
if (isc_service_query (
status,
&service_handle,
NULL,
spb - spb_buffer, spb_buffer,
sizeof(request_buffer), request_buffer,
sizeof(result_buffer), result_buffer))
{
isc_print_status(status);
isc_service_detach(status, &svc_handle);
return;
}
do
{
switch (*p++)
{
. . .
222 INTERBASE 6
QUERYING THE SERVICES MANAGER
When you interpret the identifiers in the result buffer, clusters include associated data.
The data that follow the cluster identifier are specific to the cluster type. Some clusters
have a fixed length value following the identifier, for example numeric values are always
returned as 4-byte long integers. Other clusters identifiers are followed by a 2-byte short
integer, which specifies the length of the subsequent string. Still other cluster identifiers
are followed by a series of argument identifiers with fixed or variable length data.
If the data that the Server Manager returns exceed the size of the result buffer you supply,
isc_service_query() fills the buffer as much as possible, and includes isc_info_truncated
as the last cluster identifier. This indicates that the result buffer was too small to contain
all the resulting output of the service query. To receive the entire buffer, you must call
isc_service_query() again with a larger buffer. The Services Manager starts over from the
beginning of the output; you must provide a buffer that is large enough to hold the entire
output.
EXAMPLE 12.7 Querying using Services API: handling a truncated result
. . .
case isc_info_truncated:
printf ("Buffer Truncated\n");
/* you should increase the buffer size and retry the query */
break;
. . .
For output that is typically very lengthy, such as the output of a database backup task,
the Services Manager needs to return a volume of text data. You can use the request item
isc_info_svc_line to request successive lines of the text result, or you can use
isc_info_svc_to_eof to request the entire text output in one query. See “Querying service
tasks” on page 237.
224 INTERBASE 6
QUERYING THE SERVICES MANAGER
. . .
case isc_info_svc_version:
{
unsigned long svcversion;
p += sizeof (unsigned short);
svcversion = (unsigned long)
isc_vax_integer (p, sizeof(unsigned long));
printf ("Service Manager Version: %d\n", svcversion);
p += sizeof (unsigned long);
break;
}
. . .
. . .
case isc_info_svc_server_version:
{
path_length = (unsigned short)
isc_vax_integer (p, sizeof(unsigned short));
p += sizeof (unsigned short);
buffer = (char*) malloc (path_length);
strncpy (buffer, p, path_length);
buffer [path_length] = ’\0’;
printf ("Server version: %s\n", buffer);
p += path_length;
break;
}
. . .
. . .
case isc_info_svc_implementation:
{
path_length = (unsigned short)
isc_vax_integer (p, sizeof(unsigned short));
p += sizeof (unsigned short);
buffer = (char*) malloc (path_length);
strncpy (buffer, p, path_length);
EXAMPLE 12.11 Querying using Services API: location of the server root directory
. . .
case isc_info_svc_get_env:
{
path_length = (unsigned short)
isc_vax_integer (p, sizeof(unsigned short));
p += sizeof (unsigned short);
buffer = (char*) malloc (path_length);
strncpy (buffer, p, path_length);
buffer [path_length] = ’\0’;
printf ("Value of $INTERBASE: %s\n", buffer);
free(buffer);
p += path_length;
break;
}
. . .
EXAMPLE 12.12 Querying using Services API: location of the server lock file
. . .
case isc_info_svc_get_env_lock:
{
path_length = (unsigned short)
isc_vax_integer (p, sizeof(unsigned short));
p += sizeof (unsigned short);
buffer = (char*) malloc (path_length);
strncpy (buffer, p, path_length);
buffer [path_length] = ’\0’;
printf ("Path to <hostname>.lck: %s\n", buffer);
free(buffer);
p += path_length;
break;
}
. . .
226 INTERBASE 6
QUERYING THE SERVICES MANAGER
EXAMPLE 12.13 Querying the location of the message file using the Services API
. . .
case isc_info_svc_get_env_msg:
{
path_length = (unsigned short)
isc_vax_integer (p, sizeof(unsigned short));
p += sizeof (unsigned short);
buffer = (char*) malloc (path_length);
strncpy (buffer, p, path_length);
buffer [path_length] = ’\0’;
printf ("Path to INTERBASE.MSG: %s\n", buffer);
p += path_length;
break;
}
. . .
. . .
case isc_info_svc_get_license:
{
printf ("Software activation certificates:\n");
do {
switch (*p++)
{
case isc_spb_lic_key:
{
path_length = (unsigned short)
isc_vax_integer (p, sizeof(unsigned short));
p += sizeof (unsigned short);
buffer = (char*) malloc (path_length);
strncpy (buffer, p, path_length);
buffer [path_length] = ’\0’;
printf ("\tLicense Key: %s\n", buffer);
free(buffer);
p += path_length;
break;
}
case isc_spb_lic_id:
{
path_length = (unsigned short)
isc_vax_integer (p, sizeof(unsigned short));
p += sizeof (unsigned short);
buffer = (char*) malloc (path_length);
strncpy (buffer, p, path_length);
buffer [path_length] = ’\0’;
printf ("\tLicense ID: %s\n", buffer);
free(buffer);
p += path_length;
break;
}
}
} while (*p != isc_info_flag_end);
break;
}
. . .
228 INTERBASE 6
QUERYING THE SERVICES MANAGER
. . .
case isc_info_svc_get_config:
{
unsigned short chTmp = 0, key;
unsigned long len = 0, ulConfigInfo;
break;
case ISCCFG_EVNTMEM_KEY:
printf ("\tEvent mem: %d\n", ulConfigInfo);
break;
case ISCCFG_PRIORITY_KEY:
printf ("\tPriority: %d\n", ulConfigInfo);
break;
case ISCCFG_MEMMIN_KEY:
printf ("\tMin memory: %d\n", ulConfigInfo);
break;
case ISCCFG_MEMMAX_KEY:
printf ("\tMax Memory: %d\n", ulConfigInfo);
break;
case ISCCFG_LOCKORDER_KEY:
printf ("\tLock order: %d\n", ulConfigInfo);
break;
case ISCCFG_ANYLOCKMEM_KEY:
printf ("\tAny lock mem: %d\n", ulConfigInfo);
break;
case ISCCFG_ANYLOCKSEM_KEY:
printf ("\tAny lock semaphore: %d\n",
ulConfigInfo);
break;
case ISCCFG_ANYLOCKSIG_KEY:
printf ("\tany lock sig: %d\n", ulConfigInfo);
break;
case ISCCFG_ANYEVNTMEM_KEY:
printf ("\tany event mem: %d\n", ulConfigInfo);
break;
case ISCCFG_LOCKHASH_KEY:
printf ("\tLock hash: %d\n", ulConfigInfo);
break;
case ISCCFG_DEADLOCK_KEY:
printf ("\tDeadlock: %d\n", ulConfigInfo);
break;
case ISCCFG_LOCKSPIN_KEY:
printf ("\tLock spin: %d\n", ulConfigInfo);
break;
case ISCCFG_CONN_TIMEOUT_KEY:
printf ("\tConn timeout: %d\n", ulConfigInfo);
break;
case ISCCFG_DUMMY_INTRVL_KEY:
230 INTERBASE 6
QUERYING THE SERVICES MANAGER
. . .
case isc_info_svc_get_licensed_users:
{
unsigned long nUsers;
p+= sizeof (unsigned short);
EXAMPLE 12.17 Querying using Services API: location of the security database
. . .
case isc_info_svc_user_dbpath:
{
path_length = (unsigned short)
isc_vax_integer (p, sizeof(unsigned short));
p += sizeof (unsigned short);
buffer = (char*) malloc (path_length);
strncpy (buffer, p, path_length);
buffer [path_length] = ’\0’;
printf ("Path to ISC4.GDB: %s\n", buffer);
p += path_length;
break;
}
. . .
232 INTERBASE 6
QUERYING THE SERVICES MANAGER
EXAMPLE 12.18 Querying using Services API: users configured on the server
. . .
case isc_info_svc_get_users:
{
ISC_USHORT len, loop;
ISC_ULONG id;
char buffer[50], *buf = buffer;
loop = (ISC_USHORT)
isc_vax_integer (p, sizeof (ISC_USHORT));
p += sizeof (ISC_USHORT);
break;
case isc_spb_sec_firstname:
len = (ISC_USHORT)
isc_vax_integer(p, sizeof(ISC_USHORT));
p += sizeof (ISC_USHORT);
strncpy (buf, p, len);
p += len;
buffer[len] = 0;
printf ("Firstname: %s\n", buffer);
loop -= (len + sizeof(ISC_USHORT)+1);
break;
case isc_spb_sec_middlename:
len = (ISC_USHORT)
isc_vax_integer(p, sizeof(ISC_USHORT));
p += sizeof (ISC_USHORT);
strncpy (buf, p, len);
p += len;
buffer[len] = 0;
printf ("Middlename: %s\n", buffer);
loop -= (len + sizeof(ISC_USHORT)+1);
break;
case isc_spb_sec_lastname:
len = (ISC_USHORT)
isc_vax_integer(p, sizeof(ISC_USHORT));
p += sizeof (ISC_USHORT);
strncpy (buf, p, len);
p += len;
buffer[len] = 0;
printf ("Lastname: %s\n", buffer);
loop -= (len + sizeof(ISC_USHORT)+1);
break;
case isc_spb_sec_groupid:
id = isc_vax_integer (p, sizeof (ISC_ULONG));
p += sizeof (ISC_ULONG);
printf ("Group ID: %d\n", id);
loop -= (len + sizeof(ISC_ULONG)+1);
break;
234 INTERBASE 6
QUERYING THE SERVICES MANAGER
case isc_spb_sec_userid:
id = isc_vax_integer (p, sizeof (ISC_ULONG));
p += sizeof (ISC_ULONG);
printf ("User ID: %d\n", id);
loop -= (len + sizeof(ISC_ULONG)+1);
break;
default:
*x = *p;
break;
} /* end switch */
} /* end while */
break;
}
. . .
The isc_info_svc_svr_db_info result item returns multiple sets of data. There might be
multiple active databases to report, so the result buffer might contain multiple clusters.
The contents of the buffer end when a cluster is identified with the isc_info_flag_end
value. The following table describes the cluster identifiers for the database connection
information.
. . .
case isc_info_svc_svr_db_info:
{
236 INTERBASE 6
QUERYING THE SERVICES MANAGER
. . .
}
} while (*p);
isc_service_detach(status, &service_handle);
}
238 INTERBASE 6
USING THE SERVICES API WITH DELPHI AND C++BUILDER
240 INTERBASE 6
PART II
API PartII:
Reference
Guide
Part II: API Reference Guide
Function categories
There are eleven classes of InterBase API function calls:
g Array functions for handling arrays of data
g Blob functions for handling the InterBase Blob datatype
g Database functions for handling database requests
g Conversion functions for translating dates between InterBase format and UNIX format,
and for reversing the byte-order of integers
g DSQL functions for handling SQL statements entered by users at run time
g Error-handling functions
g Event functions for registering interest in events posted by triggers and stored procedures
in applications and for processing the event queue
g Information functions for retrieving information about databases, transactions, Blob data,
and events
g Security functions for adding, deleting, and modifying user records in the password
database
g Services functions for administering server and database properties
g Transaction functions for handling transactions in an application
Some functions, such as information calls, occur in more than one class.
The embedded installation functions are not counted as part of the InterBase client API.
They typically aren’t used in database client applications, but for product installation
applications. See the Developer’s Guide for information about creating custom
installation applications using the embedded installation functions.
Array functions
The following table summarizes the InterBase API functions available for handling array
data in an application:
244 INTERBASE 6
FUNCTION CATEGORIES
Blob functions
The following table summarizes the InterBase API functions available for handling Blob
data in an application:
Database functions
The following table summarizes the InterBase API functions available for handling
database requests in an application:
Conversion functions
The following table summarizes the InterBase API functions available for translating
between InterBase DATE, TIME, and TIMESTAMP format and the UNIX date format, and for
reversing the byte-order of an integer:
246 INTERBASE 6
FUNCTION CATEGORIES
DSQL functions
The following table summarizes the InterBase API functions available for handling DSQL
statements built or entered by users at run time:
Error-handling functions
The following table summarizes the InterBase API functions available for handling
database error conditions an application:
Event functions
The following table summarizes the InterBase API functions available for handling events
in an application:
248 INTERBASE 6
FUNCTION CATEGORIES
Information functions
The following table summarizes the InterBase API functions available for reporting
information about databases, transactions, and Blob data to a client application that
requests it:
Security functions
The following table summarizes the InterBase API functions available for adding,
deleting, and modifying user records in the password database:
Services functions
The following table summarizes the InterBase API functions available for programmatic
control of server and database administration tasks:
250 INTERBASE 6
USING FUNCTION DEFINITIONS
Element Description
Title Function name
Definition Main purpose of function
Syntax Diagram of the function and parameters
Parameters Table describing each parameter
Description Detailed information about using the function
Example Example of using the function in a program
Return value Description of possible values returned in the status vector, if any
See also Cross references to other related functions
TABLE 13.12 Function description format
isc_add_user( )
Adds a user record to the password database, isc4.gdb.
Note Use of this function is deprecated. It is replaced by a full featured Services API. See
Chapter 12: “Working with Services” on page 199 and the reference entry for
“isc_service_start( )” on page 380.
At a minimum, you must provide the user name and password. If the server is not local,
you must also provide a server name and protocol. Valid choices for the protocol field are
sec_protocol_tcpip, sec_protocol_netbeui, sec_protocol_spx, and sec_protocol_local.
InterBase reads the settings for the ISC_USER and ISC_PASSWORD environment variables if
you do not provide a DBA user name and password.
The definition for the USER_SEC_DATA structure in ibase.h is as follows:
typedef struct {
short sec_flags; /* which fields are specified */
int uid; /* the user’s id */
int gid; /* the user’s group id */
int protocol; /* protocol to use for connection */
char *server; /* server to administer */
char *user_name; /* the user’s name */
char *password; /* the user’s password */
char *group_name; /* the group name */
char *first_name; /* the user’s first name */
char *middle_name; /* the user’s middle name */
char *last_name; /* the user’s last name */
char *dba_user_name; /* the dba user name */
char *dba_password; /* the dba password */
} USER_SEC_DATA;
When you pass this structure to one of the three security functions, you can tell it which
fields you have specified by doing a bitwise OR of the following values, which are defined
in ibase.h:
sec_uid_spec 0x01
sec_gid_spec 0x02
sec_server_spec 0x04
sec_password_spec 0x08
sec_group_name_spec 0x10
sec_first_name_spec 0x20
sec_middle_name_spec 0x40
sec_last_name_spec 0x80
sec_dba_user_name_spec 0x100
sec_dba_password_spec 0x200
No bit values are available for user name and password, since they are required.
252 INTERBASE 6
isc_add_user( )
Example The following example adds a user (“Socks”) to the password database, using the
bitwise OR technique for passing values from the USER_SEC_DATA structure.
{
ISC_STATUS status[20];
USER_SEC_DATA sec;
sec.server = "kennel";
sec.dba_user_name = "sysdba";
sec.dba_password = "masterkey";
sec.protocol = sec_protocol_tcpip;
sec.first_name = "Socks";
sec.last_name = "Clinton";
sec.user_name = "socks";
sec.password = "2meow!"; /* Note: do not hardcode passwords
*/
sec.sec_flags = sec_server_spec
| sec_password_spec
| sec_dba_user_name_spec
| sec_dba_password_spec
| sec_first_name_spec
| sec_last_name_spec;
isc_add_user(status, &sec);
/* check status for errors */
if (status[0] == 1 && status[1])
{
switch (status[1]) {
case isc_usrname_too_long:
printf("Security database cannot accept long user names\n");
break;
...
}
}
}
Return Value isc_add_user() returns the second element of the status vector. Zero indicates success. A
nonzero value indicates an error. See the “Description” section for this function for a list
of error codes. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_array_get_slice()
Retrieves data from an array column in a row returned by a SELECT.
254 INTERBASE 6
isc_array_get_slice()
isc_array_get_slice() retrieves data from an array column of a table row using an array
ID. You can either retrieve all the array elements in that column, or a subset of contiguous
array elements, called a slice. The upper and lower boundaries in the desc structure
specify which elements are to be retrieved.
InterBase copies the elements into the buffer, dest_array, whose size is specified by
slice_length. This should be at least the expected length required for the elements
retrieved. Before returning from isc_array_get_slice(), InterBase sets slice_length to the
actual number of bytes copied.
Before calling isc_array_get_slice(), there are many operations you must do in order to
fill in the array descriptor, desc, determine the appropriate internal array identifier,
array_id, and fetch the rows whose array columns you want to access. For complete
step-by-step instructions for setting up an array descriptor and retrieving array
information, see Chapter 8, “Working with Array Data.”
Note Never execute a DSQL statement that tries to access array column data directly
unless you are fetching only a single element. The way to access slices of array column
data is to call isc_array_get_slice() or isc_array_put_slice(). The only supported array
references in DSQL statements are ones that specify an entire array column (that is, just
the column name) in order to get the internal identifier for the array, which is required
by isc_array_get_slice() and isc_array_put_slice(), or single element references.
256 INTERBASE 6
isc_array_get_slice()
258 INTERBASE 6
isc_array_lookup_bounds()
Return Value isc_array_get_slice() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to isc_bad_stmt_handle,
isc_bad_trans_handle, or another InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_array_lookup_bounds()
Determines the datatype, length, scale, dimensions, and array boundaries for the
specified array column in the specified table.
260 INTERBASE 6
isc_array_lookup_bounds()
g Set the descriptor fields directly. Note that array_desc_dtype must be expressed as one of
the datatypes in the following table, and the parameters, array_desc_field_name, and
array_desc_relation_name, must be null-terminated:
blr_text2 CHAR
blr_short SMALLINT
blr_long INTEGER
blr_float FLOAT
blr_sql_date DATE
blr_sql_time TIME
blr_timestamp TIMESTAMP
blr_varying VARCHAR
blr_varying2 VARCHAR
ISC_STATUS status_vector[20];
ISC_ARRAY_DESC desc;
char *str1 = "PROJ_DEPT_BUDGET";
char *str2 = "QUARTERLY_HEAD_CNT";
isc_array_lookup_bounds(
status_vector,
&database_handle, /* Set in previous isc_attach_database() call. */
&tr_handle, /* Set in previous isc_start_transaction() call. */
str1,
str2,
&desc);
if (status_vector[0] == 1 && status_vector[1])
{
/* Process error. */
isc_print_status(status_vector);
return(1);
}
Return Value isc_array_lookup_bounds() returns the second element of the status vector. Zero
indicates success. A nonzero value indicates an error. For InterBase errors, the first
element of the status vector is set to 1, and the second element is set to
isc_bad_stmt_handle, isc_bad_trans_handle, isc_fld_not_def, or another InterBase
error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
262 INTERBASE 6
isc_array_lookup_desc()
isc_array_lookup_desc()
Determines the datatype, length, scale, and dimensions for all elements in the specified
array column in the specified table.
Description isc_array_lookup_desc() determines the datatype, length, scale, and dimensions for the
array column, column_name, in the table, table_name. It stores this information in the
array descriptor, desc.
It also sets to 0 a flag in the descriptor. This specifies that the array is accessed in future
function calls in row-major order, the default. If an application requires column-major
access, reset this flag to 1.
blr_text2 CHAR
blr_short SMALLINT
blr_long INTEGER
blr_float FLOAT
blr_sql_date DATE
blr_sql_time TIME
blr_timestamp TIMESTAMP
264 INTERBASE 6
isc_array_lookup_desc()
blr_varying2 VARCHAR
isc_array_lookup_desc(
status_vector,
&database_handle, /* Set in previous isc_attach_database() call. */
&tr_handle, /* Set in previous isc_start_transaction() call. */
str1,
str2,
&desc);
if (status_vector[0] == 1 && status_vector[1])
{
/* Process error. */
isc_print_status(status_vector);
return(1);
};
Return Value isc_array_lookup_desc() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to isc_bad_stmt_handle,
isc_bad_trans_handle, isc_fld_not_def, or another InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_array_put_slice()
Writes data into an array column.
266 INTERBASE 6
isc_array_put_slice()
Description isc_array_put_slice() writes data into an array column. You can either store into all the
array elements in that column, or into an array slice, a subset of contiguous array
elements. The boundaries passed to the function in the array descriptor, desc, specify
which elements are to be stored into.
InterBase copies the elements from the buffer, source_array, whose size is specified by
slice_length.
The array identifier (array ID), array_id, should be passed as NULL if you are calling
isc_array_put_slice() to create a new array. If you are calling it to modify an existing
array, then array_id should be the identifier of the array to be modified. This must have
been determined by previous calls to DSQL functions.
When isc_array_put_slice() is called with an array ID of an existing array, it:
1. Creates a new array with the same dimensions, bounds, etc., as the specified
array, and copies the existing array data to the new array.
2. Writes the data from the array buffer, source_array, to the new array (or slice
of the array), per the bounds specified in the array descriptor, desc.
3. Returns in the same array_id variable the array ID of the new array.
When isc_array_put_slice() is called with a NULL array ID, it:
1. Creates a new empty array with dimensions, bounds, etc., as declared for the
array column whose name and table name are specified in the array
descriptor, desc.
2. Writes the data from the array buffer, source_array, to the new array (or slice
of the array)
3. Returns in the array_id variable the array ID of the new array.
Note that in both cases, a new array is created, and its array ID is returned in the array_id
variable. The array is temporary until an UPDATE or INSERT statement is executed to
associate the array with a particular column of a particular row.
You can make a single call to isc_array_put_slice() to write all the data you wish to the
array. Or, you can call isc_array_put_slice() multiple times
to store data into various slices of the array. In this case, each call to isc_array_put_slice()
after the first call should pass the array ID of the temporary array. When
isc_array_put_slice() is called with the array ID of a temporary array, it copies the
specified data to the specified slice of the temporary array (it will not create a new array),
and it doesn’t modify array_id.
Before calling isc_array_put_slice(), there are many operations you must do in order to
fill in the array descriptor, desc, determine the appropriate internal array identifier,
array_id, and fetch the rows whose array columns you want to access.
For complete step-by-step instructions for setting up an array descriptor and writing array
information, see Chapter 8, “Working with Array Data.”
Note Never execute a DSQL statement that tries to directly store data into an array
column. The only way to access array column data is by calling isc_array_get_slice() or
isc_array_put_slice(). The only supported array references in DSQL statements are ones
that specify an entire array column (that is, just the column name) in order to get the
internal identifier for the array, which is required by isc_array_get_slice() and
isc_array_put_slice().
Example The following program operates on a table named PROJ_DEPT_BUDGET. This table
contains the quarterly head counts allocated for each project in each department of an
organization. Each row of the table applies to a particular department and project. The
quarterly head counts are contained in an array column named QUARTERLY_HEAD_CNT.
Each table row has four elements in this column, one per quarter. Each element is a
number of type long.
This program selects the rows containing 1994 information for the project named VBASE.
For each such row, it calls isc_array_get_slice() to retrieve a slice of the array, the
quarterly head counts for the last two quarters. It then increments each, and calls
isc_array_put_slice() to store the updated values.
In addition to illustrating the usage of isc_array_lookup_desc(), isc_array_get_slice(),
and isc_array_put_slice(), the program shows data structure initializations and calls to
the DSQL functions required to prepare and execute the SELECT and UPDATE statements,
to obtain the array_id needed by isc_array_get_slice() and isc_array_put_slice(), to
fetch the selected rows one by one, and to update the array ID.
#include <ibase.h>
268 INTERBASE 6
isc_array_put_slice()
return(1); \
}
char *sel_str =
"SELECT dept_no, quarterly_head_cnt FROM proj_dept_budget \
WHERE year = 1994 AND proj_id = ’VBASE’";
char *upd_str =
"UPDATE proj_dept_budget SET quarterly_head_count = ? \
WHERE CURRENT OF S";
char dept_no[6];
long fetch_stat, SQLCODE, hcnt[2];
short len, i, flag0, flag1, flag2;
ISC_QUAD array_id;
ISC_ARRAY_DESC desc;
ISC_STATUS status_vector[20];
isc_stmt_handle stmt = NULL;
isc_stmt_handle ustmt = NULL;
char *cursor = "S";
XSQLDA *osqlda, *isqlda;
Return_if_Error(status_vector);
/* Declare a cursor. */
isc_dsql_set_cursor_name(
status_vector, &stmt, cursor, 0);
Return_if_Error(status_vector);
270 INTERBASE 6
isc_array_put_slice()
&tr_handle,
&ustmt,
0,
upd_str,
1,
NULL);
Return_if_Error(status_vector);
/* Fetch the data from the array slice into hcnt array. */
isc_array_get_slice(
status_vector,
&database_handle,
&tr_handle,
&array_id,
&desc,
hcnt,
&len);
Return_if_Error(status_vector);
};
};
if (fetch_stat != 100L)
{
SQLCODE = isc_sqlcode(status_vector);
isc_print_sqlerror(SQLCODE, status_vector);
return(1);
}
272 INTERBASE 6
isc_array_set_desc()
Return Value isc_array_put_slice() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to isc_bad_stmt_handle,
isc_bad_trans_handle, or another InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_array_set_desc()
Initializes an array descriptor.
Description isc_array_set_desc() initializes the array descriptor, desc, from the function parameters,
table_name, column_name, sql_dtype, sql_length, and dimensions.
isc_array_set_desc() also sets to 0 a flag in the descriptor. This specifies that the array is
accessed in future function calls in row-major order, the default. If an application requires
column-major access, reset this flag to 1.
table_name and column_name can be either null-terminated or blank-terminated. The
names stored in the descriptor will be null-terminated.
sql_dtype must be given as an SQL macro constant.
The array descriptor is used in subsequent calls to isc_array_get_slice() or
isc_array_put_slice().
For a detailed description of the array descriptor, see Chapter 8, “Working with Array
Data.”
Note There are ways to fill in an array descriptor other than by calling
isc_array_set_desc(). You can also:
g Call isc_array_lookup_bounds(). This function is similar to isc_array_lookup_desc(),
except that isc_array_lookup_bounds() also fills in information about the upper and
lower bounds of each dimension.
g Call isc_array_lookup_desc(). This function is similar to isc_array_lookup_bounds(),
except that isc_array_lookup_desc() does not fill in information about the upper and
lower bounds of each dimension.
g Set the descriptor fields directly. Note that array_desc_dtype must be expressed as one of
the datatypes in the following table, and the
parameters, array_desc_field_name, and array_desc_relation_name, must be
null-terminated:
blr_text2 CHAR
blr_short SMALLINT
blr_long INTEGER
blr_float FLOAT
274 INTERBASE 6
isc_array_set_desc()
blr_sql_date DATE
blr_sql_time TIME
blr_timestamp TIMESTAMP
blr_varying VARCHAR
blr_varying2 VARCHAR
Example The following illustrates a sample call to isc_array_set_desc(). More complete examples
of accessing arrays are found in the example programs for isc_array_get_slice() and
isc_array_put_slice().
#include <ibase.h>
ISC_STATUS status_vector[20];
ISC_ARRAY_DESC desc;
short dtype = SQL_TEXT;
short len = 8;
short dims = 1;
isc_array_set_desc(
status_vector,
"TABLE1",
"CHAR_ARRAY",
&dtype,
&len,
&dims,
&desc);
if (status_vector[0] == 1 && status_vector[1])
{
/* Process error. */
isc_print_status(status_vector);
return(1);
Return Value isc_array_set_desc() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_attach_database()
Attaches to an existing database.
276 INTERBASE 6
isc_attach_database()
Example The following program fragment attaches to a database named employee.db. In the
parameter buffer, it specifies a user name and password. These come from the contents
of char * variables named user_name and user_password, respectively.
char dpb_buffer[256], *dpb, *p;
ISC_STATUS status_vector[20];
isc_db_handle handle = NULL;
short dpb_length;
*dpb++ = isc_dpb_user_name;
*dpb++ = strlen(user_name);
for (p = user_name; *p;)
*dpb++ = *p++;
*dpb++ = isc_dpb_password;
*dpb++ = strlen(user_password);
for (p = user_password; *p;)
*dpb++ = *p++;
/* An alternate choice for the above construction is to call:
isc_expand_dpb(). */
isc_attach_database(
status_vector,
0,
"employee.db",
&handle,
dpb_length,
dpb_buffer);
if (status_vector[0] == 1 && status_vector[1])
{
/* An error occurred. */
isc_print_status (status_vector);
return(1);
}
Return Value isc_attach_database() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
278 INTERBASE 6
isc_blob_default_desc()
isc_blob_default_desc()
Loads a data structure with default information about a Blob, including its subtype,
character set, and segment size.
Description isc_blob_default_desc() loads a Blob descriptor, desc, with the specified table_name
and column_name, and the following default values prior to calling
isc_blob_gen_bpb() to generate a Blob parameter buffer (BPB) for the Blob column
being accessed:
g Subtype is set to TEXT.
g Character set is set to the default character set for the process or database.
g Segment size is set to 80 bytes.
isc_blob_default_desc() and three related functions, isc_blob_gen_bpb(),
isc_blob_lookup_desc(), and isc_blob_set_desc(), provide dynamic access to Blob
information. In particular, these functions can define and access information about a
Blob for filtering purposes, such as character set information for text Blob data, and
subtype information for text and non-text Blob data.
Example The following fragment loads the Blob descriptor with default information:
typedef struct
{
short blob_desc_subtype;
short blob_desc_charset;
short blob_desc_segment_size;
unsigned char blob_desc_field_name[32];
unsigned char blob_desc_relation_name[32];
ISC_BLOB_DESC;
isc_blob_default_desc(&desc, &relation, &field);
280 INTERBASE 6
isc_blob_gen_bpb()
isc_blob_gen_bpb()
Generates a Blob parameter buffer (BPB) to allow dynamic access to Blob subtype and
character set information.
Description isc_blob_gen_bpb() generates a Blob parameter buffer (BPB) from subtype and
character set information stored in the source Blob descriptor from_desc and the target
(destination) Blob descriptor to_desc.
A BPB is needed whenever a filter will be used when writing to or reading from a Blob
column. Two Blob descriptors are needed for filtering: one (from_desc) to describe the
filter source data, and the other (to_desc) to describe the destination. The descriptors
must have been previously created either directly, or via a call to isc_blob_default_desc(),
isc_blob_lookup_desc(), or isc_blob_set_desc().
The BPB generated by isc_blob_gen_bpb() is subsequently needed in calls to
isc_open_blob2() or isc_create_blob2() if filtering will be utilized. For more information
about the BPB, see Chapter 7, “Working with Blob Data.”
Return Value isc_blob_gen_bpb() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_blob_info()
Returns information about an open Blob.
282 INTERBASE 6
isc_blob_info()
InterBase returns the requested information to the result buffer as a series of clusters of
information, one per item requested. Each cluster consists of three parts:
1. A one-byte item type. Each is the same as one of the item types in the item-list
buffer.
2. A 2-byte number specifying the number of bytes that follow in the remainder
of the cluster.
3. A value, stored in a variable number of bytes, whose interpretation depends
on the item type.
A calling program is responsible for interpreting the contents of the result buffer and for
deciphering each cluster as appropriate.
For a list of items that can be requested and returned, see Chapter 7, “Working with
Blob Data.”
Example The following example retrieves information about the current open Blob:
static char blob_items[] = {
isc_info_blob_max_segment,
isc_info_blob_num_segments,
isc_info_blob_type};
CHAR blob_info[32];
Return Value isc_blob_info() returns the second element of the status vector. Zero indicates success. A
nonzero value indicates an error. For InterBase errors, the first element of the status
vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_blob_lookup_desc()
Determines the subtype, character set, and segment size of a Blob, given a table name
and Blob column name.
Description isc_blob_lookup_desc() uses the system tables of a database to determine the subtype,
character set, and segment size of a Blob given a table name and Blob column name.
isc_blob_lookup_desc() and three related functions, isc_blob_default_desc(),
isc_blob_gen_bpb(), and isc_blob_set_desc() provide dynamic access to Blob
information. In particular, you can use these functions to define and access information
about Blob data for filtering purposes, such as character set information for text Blob
data, and subtype information for text and non-text Blob data.
284 INTERBASE 6
isc_blob_lookup_desc()
isc_blob_lookup_desc() stores the requested information about the Blob into the desc
Blob descriptor structure. The following table describes the desc structure:
Return Value isc_blob_lookup_desc() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.To
check for an InterBase error, examine the first two elements of the status vector directly.
For more information about examining the status vector, see Chapter 10, “Handling
Error Conditions.”
isc_blob_set_desc()
Sets the subtype and character set for a Blob.
Description isc_blob_set_desc() sets the Blob column name, table name, subtype, segment size, and
character set for a Blob column to values specified by the application. To set these
values to InterBase defaults, use isc_blob_default_desc().
isc_blob_set_desc() and three related functions, isc_blob_default_desc(),
isc_blob_gen_bpb(), and isc_blob_lookup_desc() provide dynamic access to Blob data.
In particular, you can use these functions to define and access information about Blob
data for filtering purposes, such as character set information for text Blob data, and
subtype information for text and non-text Blob data.
You can manually set the subtype and character set information (for a TEXT subtype) in
a Blob descriptor, by way of a call to isc_blob_set_desc(). Pass the subtype, character set,
and segment size to the Blob descriptor in your application.
286 INTERBASE 6
isc_cancel_blob()
isc_blob_set_desc() is useful for setting the contents of the Blob descriptor without
querying the system tables for the information. Calls to this function also let an
application specify character set and subtype for custom filtering operations.
Note Do not call this function while running against a V3.x database.
Example The following example sets the default values for a tour guide application, including
subtype, character set, and segment size:
isc_blob_set_desc(status, "TOURISM", "GUIDEBOOK", 1, 2, 80, &desc);
Return Value isc_blob_set_desc() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_cancel_blob()
Discards a Blob, frees internal storage used by the Blob, and sets the Blob handle to NULL.
Description InterBase temporarily stores Blob data in the database during create operations. If, for
some reason, you do not, or cannot, close a Blob, the storage space remains allocated in
the database and InterBase does not set the handle to NULL. Call isc_cancel_blob() to
release the temporary storage in the database, and to set blob_handle to NULL. If you
close the Blob in the normal course of your application processing logic, this step is
unnecessary as InterBase releases system resources on a call to isc_close_blob().
Note A call to this function does not produce an error when the handle is NULL.
Therefore, it is good practice to call isc_cancel_blob() before creating or opening a Blob
to clean up existing Blob operations.
Example The following fragment cancels any open Blob before creating a new one:
isc_cancel_blob(status_vector, &blob_handle);
if (status_vector[0] == 1 && status_vector[1])
{
/* process error */
isc_print_status(status_vector);
return(1);
}
isc_create_blob(status_vector, &DB, &trans, &blob_handle, &blob_id)
Return Value isc_cancel_blob() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
288 INTERBASE 6
isc_cancel_events()
isc_cancel_events()
Cancels an application’s interest in asynchronous notification of any of a specified group
of events.
Example The following call cancels a program’s wait for events associated with event_id, where
event_id was previously returned from a call to isc_que_events():
isc_cancel_events(status_vector, &database_handle, &event_id);
A more complete example is provided in the section on isc_que_events().
Return Value isc_cancel_events() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_close_blob()
Closes an open Blob, which involves flushing any remaining segments, releasing system
resources associated with Blob update or retrieval, and setting the Blob handle to zero.
Description isc_close_blob() is used to store a Blob in the database and clean up after Blob
operations. Close any Blob after reading from or writing to it. If, for some reason, your
application does not close a Blob, you can lose data. If your application might open a
Blob without closing it then you should call isc_cancel_blob() to make sure that the
application does not try to open a
Blob that is already open.
blob_handle is set by a call to isc_create_blob2() or to isc_open_blob2().
Example The following example closes a Blob and frees system resources:
if (status_vector[1] == isc_segstr_eof)
isc_close_blob(status_vector, &blob_handle)
Return Value isc_close_blob() returns the second element of the status vector. Zero indicates success.
A nonzero value indicates an error. For InterBase errors, the first element of the status
vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
290 INTERBASE 6
isc_commit_retaining()
isc_commit_retaining()
Commits an active transaction and retains the transaction context after a commit.
Examples The following C/C++ code commits a transaction, prints a message, and starts a new
transaction with the same handle within the same request:
if (!isc_commit_retaining(status, &retained_trans))
{
fprintf(stderr, "Committed and retained\n");
isc_print_status(status);
}
The following call commits a transaction, prints a confirmation message, starts a new
transaction with the same handle within the same request, or, if the commit fails, prints
an error message and rolls back.
isc_commit_retaining(status, &retained_trans);
if (status[0] == 1 && status[1])
{
fprintf(stderr, "Error during commit, rolling back.\n");
rb_status = isc_rollback_transaction(status, &retained_trans);
}
else
{
fprintf(stderr, "Commit successful.\n");
tr_count++; /*Increments the number of recycles. */
}
Return Value isc_commit_retaining() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_commit_transaction()
Commits a specified active transaction.
292 INTERBASE 6
isc_commit_transaction()
Description isc_commit_transaction() closes record streams, frees system resources, and sets the
transaction handle to zero for the specified transaction.
When you call this function to execute a commit operation against multiple databases,
InterBase first initiates a call to the isc_prepare_transaction() function.
isc_prepare_transaction() executes the first phase of a two-phase commit. This puts the
transaction into limbo and signals your intention to commit, so that InterBase can poll
all target databases to verify that they are ready to accept the commit. Also,
isc_commit_transaction() writes a Blob message to the RDB$TRANSACTION_DESCRIPTION
column of the RDB$TRANSACTIONS system table, detailing information required by
InterBase to perform a reconnect in case of system failure during the commit process.
The isc_commit_transaction() function also performs the second phase of a two-phase
commit upon receiving verification that all databases are ready to accept the commit.
Also, isc_commit_transaction() cleans up RDB$TRANSACTIONS.
Return Value isc_commit_transaction() returns the second element of the status vector. Zero
indicates success. A nonzero value indicates an error. For InterBase errors, the first
element of the status vector is set to 1, and the second element is set to an InterBase
error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_create_blob2()
Creates and opens the Blob for write access, and optionally specifies the filters to be used
to translate the Blob from one subtype to another.
Description isc_create_blob2() creates a context for storing a Blob, opens a Blob for write access,
and optionally specifies the filters used to translate from one Blob format to another.
Subsequent calls to isc_put_segment() write data from an application buffer to the Blob.
If a Blob filter is used, it is called for each segment written to the Blob. InterBase selects
the filter to be used based on the source and target subtypes specified in a previously
populated Blob parameter buffer (BPB), pointed to by bpb_address.
Note Blob filters are not supported on Netware.
294 INTERBASE 6
isc_create_blob2()
If a Blob filter is not needed or cannot be used, a BPB is not needed; pass 0 for bpb_length
and NULL for bpb_address.
The Blob handle pointed to by blob_handle must be zero when isc_create_blob2() is
called. To reuse blob_handle, close the Blob with a call to isc_close_blob() to zero out
the handle before calling isc_create_blob2().
On success, isc_create_blob2() assigns a unique ID to blob_handle, and a Blob identifier
to blob_id. Subsequent API calls require one or both of these to identify the Blob against
which they operate.
After a blob is created, data can be written to it by a sequence of calls to
isc_put_segment(). When finished writing to the Blob, close it with isc_close_blob().
When you create a Blob, it is essentially an “orphan” until you assign its blob_id to a
particular Blob column of a particular row of a table. You do this, after closing the Blob,
by using DSQL to execute either an INSERT statement to insert a new row containing the
Blob (and any other columns desired), or an UPDATE statement to replace an existing Blob
with the new one.
For more information about BPBs and Blob filters, see Chapter 7, “Working with Blob
Data.”
Example The following fragment declares a BPB, populates it with filter information, then creates
a Blob and passes the BPB:
isc_blob_handle blob_handle; /* declare at beginning */
ISC_QUAD blob_id; /* declare at beginning */
char bpb[] = {
isc_bpb_version1,
isc_bpb_target_type,
1, /* # bytes that follow which specify target subtype */
1, /* target subtype (TEXT) */
isc_bpb_source_type,
1, /* # bytes that follow which specify source subtype */
-4, /* source subtype*/
};
. . .
isc_create_blob2(
status_vector,
&db_handle,
&tr_handle,
&blob_handle, /* to be filled in by this function */
&blob_id, /* to be filled in by this function */
Return Value isc_create_blob2() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
296 INTERBASE 6
isc_create_database( )
isc_create_database( )
The isc_create_database( ) method is not currently supported from user applications. It
is for internal use only. Use isc_dsql_execute_immediate( ) to create a database with a
valid database handle.
isc_database_info( )
Reports requested information about a previously attached database.
g Monitor performance. For example, to compare the efficiency of two update strategies,
such as updating a sorted or unsorted stream.
The calling program passes its request for information through the item-list buffer
supplied by the program, and InterBase returns the information to a program-supplied
result buffer.
Example The following program fragment requests the page size and the number of buffers, then
examines the result buffer to retrieve the values supplied by the InterBase engine:
char db_items[] = {
isc_info_page_size, isc_info_num_buffers,
isc_info_end};
char res_buffer[40], *p, item;
int length;
SLONG page_size = 0L, num_buffers = 0L;
ISC_STATUS status_vector[20];
isc_database_info(
status_vector,
&handle, /* Set in previous isc_attach_database() call. */
sizeof(db_items),
db_items,
sizeof(res_buffer),
res_buffer);
if (status_vector[0] == 1 && status_vector[1])
{
/* An error occurred. */
isc_print_status(status_vector);
return(1);
};
/* Extract the values returned in the result buffer. */
for (p = res_buffer; *p != isc_info_end ;)
{
item = *p++;
length = isc_vax_integer (p, 2);
p += 2;
switch (item)
{
case isc_info_page_size:
page_size = isc_vax_integer (p, length);
break;
case isc_info_num_buffers:
298 INTERBASE 6
isc_decode_sql_date()
Return Value isc_database_info() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_decode_sql_date()
Translates a date from InterBase ISC_DATE format into the C struct tm format.
Description isc_decode_sql_date() translates a date retrieved from a table and stored in an ISC_DATE
variable, ib_date, into a C time structure for program manipulation. Both ib_date and
tm_date must be declared and initialized before use.
Use the isc_dsql family of API calls to retrieve InterBase DATE data from a table into the
ISC_DATE structure prior to translation.
Note In InterBase 6, the DATE datatype is available only in dialect 3. It holds only date
information, and does not include time information. In version 6 dialect 1, the TIMESTAMP
datatype holds both date and time information and is exactly equivalent to the DATE
datatype that was present in earlier versions of InterBase.
Example The following code fragment illustrates declaring time structures and calling
isc_decode_sql_date() to translate an InterBase date format into a C time format:
#include <time.h>
#include <ibase.h>
. . .
struct tm hire_time;
ISC_DATE hire_date;
. . .
/* Retrieve DATE data from a table here. */
. . .
isc_decode_sql_date(&hire_date, &hire_time);
isc_decode_sql_time()
Translates a time from InterBase ISC_TIME format into the C struct tm format.
Description isc_decode_sql_time() translates a time retrieved from a table and stored in an ISC_TIME
variable, ib_time, into a C time structure for program manipulation. Both ib_time and
tm_date must be declared and initialized before use.
Use the isc_dsql family of API calls to retrieve InterBase TIME data from a table into the
ISC_TIME structure prior to translation.
300 INTERBASE 6
isc_decode_timestamp()
Example The following code fragment illustrates declaring time structures and calling
isc_decode_sql_time() to translate an InterBase date format into a C time format:
#include <time.h>
#include <ibase.h>
. . .
struct tm hire_time;
ISC_TIME hire_date;
. . .
/* Retrieve TIME data from a table here. */
. . .
isc_decode_sql_time(&hire_date, &hire_time);
isc_decode_timestamp()
Translates a date and time from InterBase ISC_TIMESTAMP format into the C struct tm
format.
Example The following code fragment illustrates declaring time structures and calling
isc_decode_sql_timestamp() to translate an InterBase date format into a C time format:
#include <time.h>
#include <ibase.h>
. . .
struct tm hire_time;
ISC_TIMESTAMP hire_date;
. . .
/* Retrieve TIMESTAMP data from a table here. */
. . .
isc_decode_timestamp(&hire_date, &hire_time);
isc_delete_user( )
Deletes a user record from the password database, isc4.gdb.
Note Use of this function is deprecated. It is replaced by a full featured Services API. See
Chapter 12: “Working with Services” on page 199 and the reference entry for
“isc_service_start( )” on page 380.
302 INTERBASE 6
isc_delete_user( )
InterBase reads the settings for the ISC_USER and ISC_PASSWORD environment variables if
you do not provide a DBA user name and password.
The definition for the USER_SEC_DATA struct in ibase.h is as follows:
typedef struct {
short sec_flags; /* which fields are specified */
int uid; /* the user’s id */
int gid; /* the user’s group id */
int protocol; /* protocol to use for connection */
char *server; /* server to administer */
char *user_name; /* the user’s name */
char *password; /* the user’s password */
char *group_name; /* the group name */
char *first_name; /* the user’s first name */
char *middle_name; /* the user’s middle name */
char *last_name; /* the user’s last name */
char *dba_user_name; /* the dba user name */
char *dba_password; /* the dba password */
} USER_SEC_DATA;
When you pass this struct to one of the three security functions, you can tell it which
fields you have specified by doing a bitwise OR of the following values, which are defined
in ibase.h:
sec_uid_spec 0x01
sec_gid_spec 0x02
sec_server_spec 0x04
sec_password_spec 0x08
sec_group_name_spec 0x10
sec_first_name_spec 0x20
sec_middle_name_spec 0x40
sec_last_name_spec 0x80
sec_dba_user_name_spec 0x100
sec_dba_password_spec 0x200
No bit values are available for user name and password, since they are required.
Example The following example deletes a user (“Socks”) from the password database, using the
bitwise OR technique for passing values from the USER_SEC_DATA struct.
{
ISC_STATUS status[20];
USER_SEC_DATA sec;
sec.server = "kennel";
sec.dba_user_name = "sysdba";
sec.dba_password = "masterkey";
sec.protocol = sec_protocol_tcpip;
sec.user_name = "socks";
sec.sec_flags = sec_server_spec
| sec_dba_user_name_spec
| sec_dba_password_name_spec;
isc_delete_user(status, &sec);
304 INTERBASE 6
isc_detach_database()
Return Value isc_delete_user() returns the second element of the status vector. Zero indicates success.
A nonzero value indicates an error. See the “Description” section for this function for a
list of error codes. For more information about examining the status vector, see Chapter
10, “Handling Error Conditions.”
isc_detach_database()
Detaches from a database previously connected with isc_attach_database().
Assuming that handle is valid and identifies an attached database, the specified database
is detached when this statement executes.
Return Value isc_detach_database() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_drop_database()
Deletes a currently attached database and all of its supporting files, such as secondary
database files, write-ahead log files, and shadow files.
306 INTERBASE 6
isc_drop_database()
Description isc_drop_database() deletes an attached database and all of its supporting files. Call this
routine when you no longer have a use for the database (for example, if you moved all
the data into another database, or if the database was just temporary and is no longer
needed). To succeed, isc_drop_database() must be issued when no other processes are
attached to the database.
Assuming that handle is valid and identifies an attached database, the specified database
is dropped when this statement executes.
Return Value isc_drop_database() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_dsql_allocate_statement()
Allocates a statement handle for subsequent use with other API dynamic SQL (DSQL)
calls.
Example The following program fragment allocates a statement handle for an SQL statement that
will access the database referenced by the database handle, database_handle:
ISC_STATUS status_vector[20];
isc_stmt_handle statement_handle;
308 INTERBASE 6
isc_dsql_allocate_statement()
Return Value isc_dsql_allocate_statement() returns the second element of the status vector. Zero
indicates success. A nonzero value indicates an error. For InterBase errors, the first
element of the status vector is set to 1, and the second element is set to
isc_bad_stmt_handle, isc_bad_db_handle, or another InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_dsql_alloc_statement2()
Allocates a statement handle for subsequent use with other API dynamic SQL (DSQL)
calls.
Example The following program fragment allocates a statement handle for an SQL statement that
will access the database referenced by the database handle, database_handle:
ISC_STATUS status_vector[20];
isc_stmt_handle statement_handle;
isc_dsql_alloc_statement2(
status_vector,
310 INTERBASE 6
isc_dsql_alloc_statement2()
Return Value isc_dsql_alloc_statement2() returns the second element of the status vector. Zero
indicates success. A nonzero value indicates an error. For InterBase errors, the first
element of the status vector is set to 1, and the second element is set to
isc_bad_stmt_handle, isc_bad_db_handle, or another InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_dsql_describe()
Provides information about columns retrieved by the execution of a DSQL SELECT or
EXECUTE PROCEDURE statement.
Description isc_dsql_describe() stores into xsqlda a description of the columns that make up the
rows returned for a SELECT statement, or a description of the result values returned by an
EXECUTE PROCEDURE statement. These statements must have been previously prepared
for execution with isc_dsql_prepare(), before isc_dsql_describe() can be called.
Note Using isc_dsql_describe() is not necessary unless a previously issued
isc_dsql_prepare() function indicates that there is insufficient room in the output XSQLDA
for the return values of the DSQL statement to be executed.
Example The following program fragment illustrates a sequence of calls which allocates an
XSQLDA, prepares a statement, checks whether or not the appropriate number of
XSQLVARs was allocated, and corrects the situation if needed.
#include <ibase.h>
ISC_STATUS status_vector[20];
XSQLDA *osqlda;
int n;
char *query = "SELECT * FROM CITIES
WHERE STATE = ’NY’
ORDER BY CITY DESCENDING";
312 INTERBASE 6
isc_dsql_describe()
isc_dsql_prepare(
status_vector,
&tr_handle, /* Set in previous isc_start_transaction() call. */
&stmt_handle,
/* Allocated previously by isc_dsql_allocate_statement()
or isc_dsql_alloc_statement2() call. */
0,
query,
1,
osqlda);
if (status_vector[0] == 1 && status_vector[1])
{
/* Process error. */
isc_print_status(status_vector);
return(1);
}
Return Value isc_dsql_describe() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to isc_bad_stmt_handle, or
another InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_dsql_describe_bind()
Provides information about dynamic input parameters required by a previously prepared
DSQL statement.
Description isc_dsql_describe_bind() stores into the input XSQLDA xsqlda information about the
dynamic input parameters required by a DSQL statement previously prepared with
isc_dsql_prepare().
314 INTERBASE 6
isc_dsql_describe_bind()
Before an application can execute a statement with input parameters, it must supply
values for them in an input XSQLDA structure. If you know exactly how many parameters
are required, and their datatypes, you can set up the XSQLDA directly without calling
isc_dsql_describe_bind(). But if you need InterBase to analyze the statement and provide
information such as the number of parameters and their datatypes, you must call
isc_dsql_describe_bind() to supply the information.
Example The following program fragment illustrates a sequence of calls that allocates an input
XSQLDA, prepares a DSQL UPDATE statement, calls the function isc_dsql_describe_bind(),
checks whether or not the appropriate number of XSQLVARs was allocated, and corrects
the situation if necessary.
#include <ibase.h>
ISC_STATUS status_vector[20];
XSQLDA *isqlda
int n;
char *str = "UPDATE DEPARTMENT SET BUDGET = ?, LOCATION = ?";
isc_dsql_prepare(
status_vector,
&tr_handle, /* Set in previous isc_start_transaction() call. */
&stmt_handle,
/* Allocated previously by isc_dsql_allocate_statement()
or isc_dsql_alloc_statement2() call. */
0,
str,
1,
NULL);
if (status_vector[0] == 1 && status_vector[1])
{
/* Process error. */
isc_print_status(status_vector);
return(1);
}
/* Allocate an input XSQLDA. */
isqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(1);
isqlda->version = SQLDA_VERSION1;
isqlda->sqln = 1;
isc_dsql_describe_bind(
status_vector,
&stmt_handle,
/* Allocated previously by isc_dsql_allocate_statement()
or isc_dsql_alloc_statement2() call. */
1,
isqlda);
if (status_vector[0] == 1 && status_vector[1])
{
/* Process error. */
isc_print_status(status_vector);
return(1);
}
if (isqlda->sqld > isqlda->sqln) /* Need more XSQLVARs. */
{
n = isqlda->sqld;
free(isqlda);
isqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(n);
isqlda->sqln = n;
isqlda->version = SQLDA_VERSION1;
isc_dsql_describe_bind(
status_vector,
&stmt_handle,
1,
isqlda);
if (status_vector[0] == 1 && status_vector[1])
{
/* Process error. */
isc_print_status(status_vector);
return(1);
}
}
Return Value isc_dsql_describe_bind() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to isc_bad_stmt_handle, or
another InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
316 INTERBASE 6
isc_dsql_execute()
isc_dsql_execute()
Executes a previously prepared DSQL statement.
Note To execute a statement repeatedly when it both has input parameters and return
values, such as EXECUTE PROCEDURE, use isc_dsql_execute2() which requires both an
input and an output XSQLDA.
If you only need to execute a statement once, and it does not return any data, call
isc_dsql_execute_immediate() instead of isc_dsql_prepare() and isc_dsql_execute(). To
execute a statement with both input and output parameters a single time, use
isc_dsql_exec_immed2().
Note CREATE DATABASE and SET TRANSACTION cannot be executed with isc_dsql_execute()
or isc_dsql_execute2(). To execute these statements, use isc_dsql_execute_immediate().
318 INTERBASE 6
isc_dsql_execute()
/* Check to see whether or not the output XSQLDA had enough XSQLVARS
allocated. If not, correct it -- see isc_dsql_describe(). */
/* Allocate and fill in the input XSQLDA. This example assumes you know
how many input parameters there are (1), and all other information
necessary to supply a value. If this is not true, you will need to call
isc_dsql_describe_bind(). */
isqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(1));
isqlda->version = SQLDA_VERSION1;
isqlda->sqln = 1;
isqlda->sqld = 1;
ivar = isqlda->sqlvar[0];
ivar->sqltype = SQL_TEXT;
ivar->sqllen = sizeof(state);
ivar->sqldata = state;
/* Fetch and process the rows in the select list one by one. */
while ((fetch_stat = isc_dsql_fetch(
status_vector,
&stmt_handle,
1,
osqlda)) == 0)
{
for (i=0; i < osqlda->sqld; i++)
{
/* Call a function you’ve written to process each returned
select-list item. */
process_column(osqlda->sqlvar[i]);
}
}
Return Value isc_dsql_execute() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to isc_bad_stmt_handle,
isc_bad_trans_handle, or another InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
320 INTERBASE 6
isc_dsql_execute2()
isc_dsql_execute2()
Executes a previously prepared DSQL statement.
Description isc_dsql_execute2() executes a previously prepared DSQL statement that has input
parameters and returns results, such as EXECUTE PROCEDURE and SELECT.
If the statement to execute requires input parameter values (that is, if it contains
parameter markers), these values must be supplied in the input XSQLDA, in_xsqlda before
calling isc_dsql_execute2().
If the statement to execute returns values, they are placed in the specified output XSQLDA,
out_xsqlda. If a NULL value is supplied for the output XSQLDA and the statement returns
values, they are stored in a result set. To access the returned data, use isc_dsql_fetch() in
a loop.
Tip If you just want to execute once a statement returning just one group of data, call
isc_dsql_exec_immed2() instead of isc_dsql_prepare() and isc_dsql_execute2().
To execute a statement that does not return any data a single time, call
isc_dsql_execute_immediate() instead of isc_dsql_prepare() and isc_dsql_execute2().
Note CREATE DATABASE and SET TRANSACTION cannot be executed with isc_dsql_execute()
or isc_dsql_execute2(). To execute these statements, use isc_dsql_execute_immediate().
Example The following program fragment illustrates a sequence of calls that allocates an input
XSQLDA and loads values into it, allocates an output XSQLDA, prepares an EXECUTE
PROCEDURE statement, allocates space in the output XSQLDA for each column returned
for each row retrieved by the call, and executes the prepared statement, placing return
values in the output XSQLDA.
#include <ibase.h>
ISC_STATUS status_vector[20];
XSQLDA *isqlda, *osqlda;
XSQLVAR *ivar, *ovar;
short null_flag;
char *str = "EXECUTE PROCEDURE P1";
char *state = "CA";
/* Allocate an output XSQLDA osqlda. This example assumes you know that
P1 will return one value. */
osqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(1);
osqlda->version = SQLDA_VERSION1;
osqlda->sqln = 1;
322 INTERBASE 6
isc_dsql_execute2()
osqlda);
if (status_vector[0] == 1 && status_vector[1])
{
/* Process error. */
isc_print_status(status_vector);
return(1);
}
/* Set up the output XSQLVAR structure to allocate space for the return
value. Again, this example assumes you know that P1 returns just one
value. For an example of what to do if you’re not sure, see
isc_dsql_describe(). For an example of setting up an output XSQLVAR
structure to allocate space for multiple return items, see the
isc_dsql_execute() example program. */
ovar = osqlda->sqlvar[0];
dtype = (ovar->sqltype & ~1); /* Drop NULL bit for now. */
switch(dtype)
{
case SQL_TEXT:
ovar->sqldata = (char *)malloc(sizeof(char) * ovar->sqllen);
break;
case SQL_LONG:
ovar->sqldata = (char *)malloc(sizeof(long));
/* Process remaining types. */
. . .
}
if (ovar->sqltype & 1)
{
/* Assign a variable to hold NULL status. */
ovar->sqlind = &null_flag;
}
/* Allocate and fill in the input XSQLDA. This example assumes you know
how many input parameters there are (1), and all other information
necessary to supply a value. If this is not true, you will need to call
isc_dsql_describe_bind(). */
isqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(1);
isqlda->version = SQLDA_VERSION1;
isqlda->sqln = 1;
isqlda->sqld = 1;
ivar = isqlda->sqlvar[0];
ivar->sqltype = SQL_TEXT;
ivar->sqllen = sizeof(state);
ivar->sqldata = state;
Return Value isc_dsql_execute2() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to isc_bad_stmt_handle,
isc_bad_trans_handle, or another InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
324 INTERBASE 6
isc_dsql_execute_immediate()
isc_dsql_execute_immediate()
Prepares and executes just once a DSQL statement that does not return data. There is a
special case of isc_dsql_execute_immediate() for creating databases.
Note In the special case where the statement is CREATE DATABASE, there is no transaction,
so db_handle and trans_handle must be pointers to handles whose value is NULL. When
isc_dsql_execute_immediate() returns, db_handle is a valid handle, just as though you
had made a call to isc_attach_database().
Tip If statement returns data, or if it needs to be executed more than once, use
isc_dsql_prepare() and isc_dsql_execute() (or isc_dsql_execute2()) instead of
isc_dsql_execute_immediate().
Note You must call isc_dsql_execute_immediate() rather than isc_dsql_prepare() and
isc_dsql_execute() for CREATE DATABASE or SET TRANSACTION. To start a transaction, you
also have the option of using isc_start_transaction().
isc_dsql_execute_immediate(
status_vector,
&database_handle, /* Set in previous isc_attach_database() call. */
&tr_handle, /* Set in previous isc_start_transaction() call. */
0,
insert_stmt,
1,
NULL);
326 INTERBASE 6
isc_dsql_execute_immediate()
isc_dsql_execute_immediate(
status_vector,
&db_handle,
&dummy_handle,
0,
statement,
1,
NULL);
if (status_vector[0] == 1 && status_vector[1])
{
/* Process error. */
isc_print_status(status_vector);
return(1);
}
Return Value isc_dsql_execute_immediate() returns the second element of the status vector. Zero
indicates success. A nonzero value indicates an error. For InterBase errors, the first
element of the status vector is set to 1, and the second element is set to
isc_bad_db_handle, isc_bad_trans_handle, or another InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
For more information about creating and populating the XSQLDA, see “Understanding
the XSQLDA” on page 85.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_dsql_exec_immed2()
Prepares and executes just once, a DSQL statement that returns no more than one row of
data.
328 INTERBASE 6
isc_dsql_exec_immed2()
Return Value isc_dsql_exec_immed2() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to isc_bad_db_handle,
isc_bad_trans_handle, or another InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_dsql_fetch()
Retrieves data returned by a previously prepared and executed DSQL statement.
Description isc_dsql_fetch() retrieves one row of data into xsqlda each time it is called. It is used in
a loop to retrieve and process each row of data for statements that return multiple rows
in a cursor.
330 INTERBASE 6
isc_dsql_fetch()
A cursor is a one-way pointer into the ordered set of rows retrieved by a statement. A
cursor is only needed to process positioned UPDATE and DELETE statements made against
the rows retrieved by isc_dsql_fetch() for SELECT statements that specify an optional FOR
UPDATE OF clause.
It is up to the application to provide the loop construct for fetching the data.
Before calling isc_dsql_fetch(), a statement must be prepared with isc_dsql_prepare(),
and executed with isc_dsql_execute() (or isc_dsql_execute2() with a NULL output xsqlda
argument). Statement execution produces a result set containing the data returned. Each
call to isc_dsql_fetch() retrieves the next available row of data from the result set into
xsqlda.
Example The following program fragment illustrates a sequence of calls that allocates an output
XSQLDA, prepares a statement for execution, allocates an XSQLVAR structure in the XSQLDA
for each column of data to be retrieved, executes the statement, producing a select list of
returned data, then fetches and processes each row in a loop:
#include <ibase.h>
#define LASTLEN 20
#define FIRSTLEN 15
#define EXTLEN 4
typedef struct vary {
short vary_length;
char vary_string[1];
} VARY;
ISC_STATUS status_vector[20], retcode;
long SQLCODE;
XSQLDA *osqlda;
XSQLVAR *ovar;
short flag0, flag1, flag2;
char *str =
"SELECT last_name, first_name, phone_ext FROM phone_list
WHERE location = "Monterey" ORDER BY last_name, first_name";
char last_name[LASTLEN + 2];
char first_name[FIRSTLEN + 2];
char phone_ext[EXTLEN + 2];
VARY *vary;
/* Allocate an output XSQLDA osqlda. */
osqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(3);
osqlda->version = SQLDA_VERSION1;
osqlda->sqln = 3;
/* Prepare the statement. */
isc_dsql_prepare(
status_vector,
&tr_handle, /* Set in previous isc_start_transaction() call. */
&stmt_handle,
/* Allocated previously by isc_dsql_allocate_statement()
or isc_dsql_alloc_statement2() call. */
0,
str,
1,
osqlda);
if (status_vector[0] == 1 && status_vector[1])
{
/* Process error. */
isc_print_status(status_vector);
return(1);
}
/* Set up an output XSQLVAR structure to allocate space for each item
to be returned. */
osqlda->sqlvar[0].sqldata = last_name;
osqlda->sqlvar[0].sqltype = SQL_VARYING + 1;
osqlda->sqlvar[0].sqlind = &flag0;
osqlda->sqlvar[1].sqldata = first_name;
osqlda->sqlvar[1].sqltype = SQL_VARYING + 1;
osqlda->sqlvar[1].sqlind = &flag1;
osqlda->sqlvar[2].sqldata = phone_ext;
osqlda->sqlvar[2].sqltype = SQL_VARYING + 1;
osqlda->sqlvar[2].sqlind = &flag2;
/* Execute the statement. */
isc_dsql_execute(
status_vector,
&tr_handle, /* Set in previous isc_start_transaction() call. */
&stmt_handle,
/* Allocated previously by isc_dsql_allocate_statement()
or isc_dsql_alloc_statement2() call. */
1,
NULL);
if (status_vector[0] == 1 && status_vector[1])
{
/* Process error. */
isc_print_status(status_vector);
return(1);
}
332 INTERBASE 6
isc_dsql_fetch()
Return Value isc_dsql_fetch() returns the second element of the status vector. Zero indicates success.
The value 100 indicates that no more rows remain to be retrieved. Any other nonzero
value indicates an error. For InterBase errors, the first element of the status vector is set
to 1, and the second element is set to isc_bad_stmt_handle, or another InterBase error
code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_dsql_free_statement()
Frees a statement handle and all resources allocated for it, or closes a cursor associated
with the statement referenced by a statement handle.
Description isc_dsql_free_statement() either frees a statement handle and all resources allocated for
it (option = DSQL_drop), or closes a cursor associated with the statement (option =
DSQL_close).
Note isc_dsql_free_statement() does nothing if it is called with an option value other
than DSQL_drop or DSQL_close.
4 DSQL_close
Call isc_dsql_free_statement() with the DSQL_close option to close a cursor after it is no
longer needed, that is, after fetching and processing all the rows resulting from the
execution of a query. A cursor need only be closed in this manner if it was previously
opened and associated with stmt_handle by isc_dsql_set_cursor_name().
DSQL_close closes a cursor, but the statement it was associated with remains available for
further execution.
If you have used a cursor to perform updates or deletes on all the rows returned from the
execution of a query, and you want to perform other update or delete operations on rows
resulting from execution of the same statement again (possibly with different input
parameters), follow these steps:
1. Close the cursor with isc_dsql_free_statement().
2. Re-open it with isc_dsql_set_cursor_name().
334 INTERBASE 6
isc_dsql_free_statement()
4 DSQL_drop
Statement handles allocated with isc_dsql_allocate_statement() must be released when
no longer needed by calling isc_dsql_free_statement() with the DSQL_drop option. This
option frees all resources associated with the statement handle, and closes any open
cursors associated with the statement handle.
Example The following program fragment shows examples of the two types of
isc_dsql_free_statement() calls. It assumes that stmt_handle1 and stmt_handle2 are
statement handles, each of which was previously allocated with either
isc_dsql_allocate_statement() or isc_dsql_alloc_statement2(). A cursor is also assumed
to have been associated with the statement referenced by stmt_handle1.
#include <ibase.h>
ISC_STATUS status_vector[20];
. . .
/* Free the cursor associated with stmt_handle1. */
isc_dsql_free_statement(
status_vector,
&stmt_handle1,
DSQL_close);
if (status_vector[0] == 1 && status_vector[1])
{
isc_print_status(status_vector);
return(1);
}
/* Free stmt_handle2. */
isc_dsql_free_statement(
status_vector,
&stmt_handle2,
DSQL_drop);
if (status_vector[0] == 1 && status_vector[1])
{
isc_print_status(status_vector);
return(1);
}
Return Value isc_dsql_free_statement() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to isc_bad_stmt_handle, or
another InterBase error code.To check for an InterBase error, examine the first two
elements of the status vector directly. For more information about examining the status
vector, see Chapter 10, “Handling Error Conditions.”
isc_dsql_prepare()
Prepares a DSQL statement for repeated execution.
336 INTERBASE 6
isc_dsql_prepare()
Description isc_dsql_prepare() readies the DSQL statement specified in statement for repeated
execution by checking it for syntax errors and parsing it into a format that can be
efficiently executed. All SELECT statements must be prepared with isc_dsql_prepare().
After a statement is prepared, it is available for execution as many times as necessary
during the current session. Preparing a statement for repeated execution is more efficient
than using isc_dsql_execute_immediate() or isc_dsql_exec_immed2() over and over
again to prepare and execute a statement.
If a statement to be prepared does not return data, set the output XSQLDA to NULL.
Otherwise, the output XSQLDA must be allocated prior to calling isc_dsql_prepare().
Allocate the XSQLDA using the macro, XSQLDA_LENGTH, defined in ibase.h, as follows:
xsqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(n));
XSQLDA_LENGTH calculates the number of bytes required when n result columns will be
returned by the statement, and allocates the appropriate amount of storage.
After allocating the XSQLDA xsqlda, set xsqlda->version to SQLDA_VERSION1, and set
xsqlda_sqln to indicate the number of XSQLVAR structures allocated.
When isc_dsql_prepare() is called, it fills in the other fields of the XSQLDA and all the
XSQLVARs with information such as the datatype, length, and name of the corresponding
select-list items in the statement. It fills in xsqlda->sqld with the actual number of
select-list items returned. If xsqlda->sqld is greater than xsqlda->sqln, then enough room
is not allocated, and the XSQLDA must be resized by following these steps:
1. Record the current value of the xsqlda->sqld.
2. Free the storage previously allocated for xsqlda.
3. Reallocate storage for xsqlda, this time specifying the correct number (from
step 1) in the argument to XSQLDA_LENGTH.
4. Reset xsqlda->sqld and xsqlda->version.
5. Execute isc_dsql_describe() to fill in the xsqlda fields.
Note If the prepared statement requires input parameter values, then an input XSQLDA
will need to be allocated and filled in with appropriate values prior to calling
isc_dsql_execute() or isc_dsql_execute2(). You can either allocate and directly fill in all
the fields of the input XSQLDA, or you can allocate it, call isc_dsql_describe_bind() to get
information regarding the number and types of parameters required, then fill in
appropriate values.
Example The following program fragment illustrates the allocation of the output XSQLDA, and a
call to isc_dsql_prepare():
#include <ibase.h>
ISC_STATUS status_vector[20];
XSQLDA *osqlda;
char *query = "SELECT CITY, STATE, POPULATION FROM CITIES \
WHERE STATE = "NY" ORDER BY CITY DESCENDING";
isc_dsql_prepare(
status_vector,
&tr_handle, /* Set in previous isc_start_transaction() call. */
&stmt_handle,
/* Allocated previously by isc_dsql_allocate_statement()
or isc_dsql_alloc_statement2() call. */
0,
query,
1,
osqlda);
if (status_vector[0] == 1 && status_vector[1])
{
isc_print_status(status_vector);
return(1);
}
More complete examples showing the subsequent execution and fetching of result data
are provided in the example programs for isc_dsql_execute(), isc_dsql_execute2(), and
isc_dsql_fetch().
338 INTERBASE 6
isc_dsql_set_cursor_name()
Return Value isc_dsql_prepare() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to isc_bad_stmt_handle,
isc_bad_trans_handle, or another InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_dsql_set_cursor_name()
Defines a cursor name and associates it with a DSQL statement.
A cursor is a one-way pointer into the ordered set of rows retrieved by a statement. A
cursor is only needed to process positioned UPDATE and DELETE statements made against
the rows retrieved by isc_dsql_fetch() for SELECT statements that specify an optional FOR
UPDATE OF clause.
Example The following pseudo-code illustrates the calling sequence necessary to execute an
UPDATE or DELETE with the WHERE CURRENT OF clause using a cursor name established
and opened with isc_dsql_set_cursor_name():
#include <ibase.h>
ISC_STATUS status_vector[20], fetch_stat;
isc_stmt_handle st_handle = NULL;
char *cursor = "S";
340 INTERBASE 6
isc_dsql_set_cursor_name()
return(1);
}
/* Fetch rows one by one, with the cursor pointing to each row as it
is fetched, and execute an UPDATE or DELETE statement to update or
delete the row pointed to by the cursor. */
while ((fetch_stat = isc_dsql_fetch(
status_vector, &st_handle, 1, osqlda)) == 0)
{
. . .
/* Update or delete the current row by executing an "UPDATE ...
WHERE CURRENT OF S" or "DELETE ... WHERE CURRENT OF S"
statement, where "S" is the name of the cursor declared in
isc_dsql_set_cursor_name(). */
}
Return Value isc_dsql_set_cursor_name() returns the second element of the status vector. Zero
indicates success. A nonzero value indicates an error. For InterBase errors, the first
element of the status vector is set to 1, and the second element is set to
isc_bad_stmt_handle, or another InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_dsql_sql_info()
Returns requested information about a prepared DSQL statement.
342 INTERBASE 6
isc_dsql_sql_info()
Example The following illustrates a call to isc_dsql_sql_info() to determine the statement type of
the statement whose handle is referenced by stmt:
int statement_type;
int length;
char type_item[] = {isc_info_sql_stmt_type};
char res_buffer[8];
isc_dsql_sql_info(
status_vector,
&stmt,
/* Allocated previously by isc_dsql_allocate_statement() or
isc_dsql_alloc_statement2() call. */
sizeof(type_item),
type_item,
sizeof(res_buffer),
res_buffer);
if (res_buffer[0] == isc_info_sql_stmt_type)
{
length = isc_vax_integer(buffer[1], 2);
statement_type = isc_vax_integer(buffer[3], length);
}
Return Value isc_dsql_sql_info() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_encode_sql_date()
Translates a date from the C struct tm format to InterBase ISC_DATE format prior to
inserting or updating a DATE value in a table.
Example The following code fragment illustrates declaring time structures and calling
isc_encode_sql_date() to translate a C time format into an InterBase date format prior to
inserting or updating a table:
#include <time.h>
#include <ibase.h>
. . .
struct tm hire_time;
ISC_DATE hire_date;
. . .
/* Store date info into the tm struct here. */
. . .
isc_encode_sql_date(&hire_time, &hire_date);
/* Now use a DSQL INSERT or UPDATE statement to move the date into a
DATE column. */
344 INTERBASE 6
isc_encode_sql_time()
isc_encode_sql_time()
Translates a time from the C struct tm format to InterBase ISC_SQL_TIME format prior to
inserting or updating a TIME value in a table.
Example The following code fragment illustrates declaring time structures and calling
isc_encode_sql_time() to translate a C time format into an InterBase date format prior to
inserting or updating a table:
#include <time.h>
#include <ibase.h>
. . .
struct tm hire_time;
ISC_TIME hire_date;
. . .
/* Store time info into the tm struct here. */
. . .
isc_encode_sql_time(&hire_time, &hire_date);
/* Now use a DSQL INSERT or UPDATE statement to move the date into a
TIME column. */
isc_encode_timestamp()
Translates a time from the C struct tm format to InterBase ISC_TIMESTAMP format prior to
inserting or updating a TIMESTAMP value in a table.
Example The following code fragment illustrates declaring time structures and calling
isc_encode_timestamp() to translate a C time format into an InterBase date format prior
to inserting or updating a table:
#include <time.h>
#include <ibase.h>
. . .
struct tm hire_time;
ISC_TIMESTAMP hire_date;
. . .
/* Store date and time info into the tm struct here. */
. . .
isc_encode_timestamp (&hire_time, &hire_date);
346 INTERBASE 6
isc_event_block()
/* Now use a DSQL INSERT or UPDATE statement to move the date into a
TIMESTAMP column. */
isc_event_block()
Allocates two event parameter buffers (EPBs) for subsequent use with other API event
calls.
Description isc_event_block() must be called before any other event functions. It:
g Allocates two event parameter buffers of the same size, and stores their addresses into the
character pointers addressed by event_buffer and result_buffer.
g Stores into the buffer referenced by event_buffer the names and event counts for each of
the specified events. The names are the ones that appear as the final arguments to
isc_event_block(). The event counts are initialized to zero and are used to specify how
many times each event has been posted prior to each wait for events to occur.
g Returns the length, in bytes, of the buffers.
The buffers, and their lengths, are used in subsequent calls to the functions
isc_wait_for_event(), isc_que_events(), and isc_event_counts(). event_buffer is used to
indicate the events of interest, and to hold the counts in effect before a wait for one of
the events. After an event is posted, result_buffer is filled in exactly as event_buffer,
except that the event counts are updated. isc_event_counts() is then called to determine
which events were posted between the time the counts were set in event_buffer, and the
time the counts are set in result_buffer.
length = isc_event_block(
&event_buffer,
&result_buffer,
number_of_stocks,
"DEC", "HP", "SUN");
Return Value isc_event_block() returns a number that is the size, in bytes, of each event parameter
buffer it allocates.
348 INTERBASE 6
isc_event_counts()
isc_event_counts()
Compares event parameter buffers (EPBs) to determine which events have been posted,
and prepares the event parameter buffers for the next call to isc_que_events() or
isc_wait_for_event().
Description isc_event_counts() compares the event counts in the event parameter buffers,
event_buffer and result_buffer, and sets up to the first 15 elements of status_array to
contain the differences. It then modifies event_buffer to contain the same event counts
as result_buffer in preparation for the next call to either isc_wait_for_event() or
isc_que_events().
The counts in event_buffer specify how many times each event had been posted since
the previous call to isc_event_wait() or isc_que_events(). The counts in result_buffer
equal the values in event_buffer plus the number of additional times an event is posted
after the current call to isc_event_wait() or isc_que_events(). If an event is posted after
a call to either of these functions, its count is greater in result_buffer than in event_buffer.
Other event counts may also be greater because an event may have been posted between
calls to either of these functions. The values in status_array are the differences in values
between event_buffer and result_buffer. This mechanism of comparing all the counts
ensures that no event postings are missed.
Example The following program fragment illustrates the set-up and waiting on any of the events
named “DEC”, “HP”, or “SUN”, then calling isc_event_counts() to determine which
events have been posted:
#include <ibase.h>
#define number_of_stocks 3;
length = isc_event_block(
&event_buffer,
&result_buffer,
number_of_stocks,
"DEC", "HP", "SUN");
isc_wait_for_event(
status_vector,
&database_handle, /* Set by previous isc_attach_database(). */
length, /* Returned from isc_event_block(). */
event_buffer,
result_buffer);
if (status_vector[0] == 1 && status_vector[1])
{
isc_print_status(status_vector); /* Display error message. */
return(1);
}
isc_event_counts(
status_vector,
(short) length,
event_buffer,
result_buffer);
350 INTERBASE 6
isc_expand_dpb( )
isc_expand_dpb( )
Dynamically builds or expands a database parameter buffer (DPB) to include database
parameters.
Description isc_expand_dpb() builds or expands a DPB dynamically. Its main use is to simplify the
building of the DPB prior to a call to isc_attach_database(), or to allow an end user to
supply a user name and password combination at run time. In many cases, the DPB
must be constructed programmatically, but isc_expand_dpb() enables an application to
pass user names, password, message file, and character set parameters to the function,
which then adds them to an existing DPB.
A pointer to a previously allocated and initialized DPB must be passed to
isc_expand_dpb() along with a pointer to a variable containing the current size of the
DPB when this function is called. If the space allocated for the DPB is not large enough
for the parameters passed to isc_expand_dpb(), then the function reallocates a larger
DPB, preserving its current contents, and adds the new parameters.
To ensure proper memory management, applications that call isc_expand_dpb() should
always allocate DPBs large enough to hold all anticipated parameters.
Example The following code calls isc_expand_dpb() to create a DPB, then attaches to a database
using the newly created DPB. user_name and user_password are assumed to be
variables whose values have been filled in, for example, after asking the user to specify
the name and password to be used.
#include <ibase.h>
char *dpb;
ISC_STATUS status_vector[20];
isc_db_handle handle = NULL;
short dpb_length;
isc_attach_database(
status_vector,
0,
"employee.db",
&handle,
dpb_length,
dpb_buffer);
if (status_vector[0] == 1 && status_vector[1])
{
/* An error occurred. */
isc_print_status(status_vector);
return(1);
}
352 INTERBASE 6
isc_get_segment( )
isc_get_segment( )
Reads a segment from an open Blob.
Description isc_get_segment() reads a Blob segment from a previously opened Blob. You can set the
seg_buffer_length parameter to a size that is efficient for a particular type of Blob data.
For example, if you are reading Blob data from a text file, you might set the segment
buffer length to 80, to take advantage of the 72 to 80 character line lengths that are
common in text files. By periodically checking the value of the actual segment length in
your loop, you can determine an end-of-line or end-of-file condition.
Before reading any part of a Blob, you must open the Blob with a call to
isc_open_blob2(). isc_get_segment() behaves differently depending on which call
precedes it. If the most recent call is to isc_open_blob2(), then a call to isc_get_segment()
reads the first segment in the Blob. If the most recent call is to isc_get_segment(), then it
reads the next segment.
If Blob filters are specified when a Blob is opened, then each segment retrieved by
isc_get_segment() is filtered on read.
Note Blob filters are not supported on NetWare.
You can read bitmaps and other binary files directly, without filtering, if you don’t need
to change from one format to another, say from .TIF to .JPEG. You can also store
compressed bitmaps directly in a database in formats such as .JPG ( JPEG), .BMP (Windows
native bitmaps), or .GIF (CompuServe Graphic Interchange Format). No filtering is
required.
You can store bitmaps in a database in row-major or column-major order.
If the buffer is not large enough to hold the entire current segment, the function returns
isc_segment, and the next call to isc_get_segment() gets the next chunk of the oversized
segment rather than getting the next segment.
When isc_get_segment() reads the last segment of the Blob, the function returns the code
isc_segstr_eof.
For more information about reading data from a Blob, see Chapter 7, “Working with
Blob Data.”
Example The following call gets a segment from one Blob and writes it to another:
get_status = isc_get_segment(status, &from_blob, &seg_len, 80,
buffer);
if (status[0] == 1 && status[1])
{
isc_print_status(status);
return(1);
}
if (get_status != isc_segstr_eof)
write_status = isc_put_segment(status, &to_blob, seg_len, buffer);
if (status[0] == 1 && status[1])
{
isc_print_status(status);
return(1);
}
Return Value isc_get_segment() returns the second element of the status vector. Zero indicates
success. isc_segment indicates the buffer is not large enough to hold the entire current
segment; the next call to isc_get_segment() gets the next chunk of the oversized
segment rather than getting the next segment. isc_segstr_eof indicates that the last
segment of the Blob has been read. Any other nonzero value indicates an error. For
InterBase errors, the first element of the status vector is set to 1, and the second element
is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
354 INTERBASE 6
isc_interprete()
isc_interprete()
Extracts the text for an InterBase error message from the error status vector to a
user-defined buffer.
Description Given both the location of a storage buffer allocated in a program, and the address of
the status vector, isc_interprete() builds an error message string from the information in
the status vector, puts the formatted string in the buffer where the program can
manipulate it, and advances the status vector pointer to the start of the next cluster of
error message information. For example, you might declare an error string buffer, call
isc_interprete() to retrieve the first error message and insert the message into the buffer,
write the buffer to a log file, then peek at the next cluster to see if it contains more error
information.
isc_interprete() retrieves and formats a single message each time it is called. When an
error occurs, however, the status vector usually contains more than one error message.
To retrieve all relevant error messages, you must make repeated calls to isc_interprete()
until no more messages are returned.
Note Do not pass the address of the status vector directly, because each time
isc_interprete() is called, it modifies the pointer to the status vector to point to the start
of the next available message.
To display all error messages on the screen instead of to a buffer, use isc_print_status().
Example The following code declares a message buffer, a status vector, and a pointer to the
vector, then illustrates how repeated calls are made to isc_interprete() to store all
messages in the buffer:
#include <ibase.h>
char msg[512];
ISC_STATUS status_vector[20];
Return Value If successful, isc_interprete() returns the length of the error message string it stores in
buffer. It also advances the status vector pointer to the start of the next cluster of error
message information.
If there are no more messages in the status vector, or if isc_interprete() cannot interpret
the next message, it returns 0.
isc_modify_user( )
Modifies a user record from the password database, isc4.gdb.
Note Use of this function is deprecated. It is replaced by a full featured Services API. See
Chapter 12: “Working with Services” on page 199 and the reference entry for
“isc_service_start( )” on page 380.
356 INTERBASE 6
isc_modify_user( )
When you pass this struct to one of the three security functions, you can tell it which
fields you have specified by doing a bitwise OR of the following values, which are defined
in ibase.h:
sec_uid_spec 0x01
sec_gid_spec 0x02
sec_server_spec 0x04
sec_password_spec 0x08
sec_group_name_spec 0x10
sec_first_name_spec 0x20
sec_middle_name_spec 0x40
sec_last_name_spec 0x80
sec_dba_user_name_spec 0x100
sec_dba_password_spec 0x200
No bit values are available for user name and password, since they are required.
The following error messages exist for this function:
Example The following example modifies isc4.gdb to change the password for the user Socks,
using the bitwise OR technique for passing values from the USER_SEC_DATA struct.
{
ISC_STATUS status[20];
USER_SEC_DATA sec;
sec.server = "kennel";
sec.dba_user_name= "sysdba";
sec.dba_password = "masterkey";
sec.protocol = sec_protocol_tcpip;
sec.user_name = "socks";
358 INTERBASE 6
isc_modify_user( )
isc_add_user(status, &sec);
/* check status for errors */
if (status[0] == 1 && status[1])
{
switch (status[1]) {
case isc_usrname_too_long:
printf("Security database cannot accept long user names\n");
break;
...
}
}
}
Return Value isc_modify_user() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. See the “Description” section for this
function for a list of error codes. For more information about examining the status
vector, see Chapter 10, “Handling Error Conditions.”
isc_open_blob2()
Opens an existing Blob for retrieval and optional filtering.
Description isc_open_blob2() opens an existing Blob for retrieval and optional filtering from one
Blob subtype to another.
Note Using Blob filters is not supported on NetWare.
Input and output Blob filter types are passed to isc_open_blob2() as subtype information
in a previously populated BPB, pointed to by bpb_address. If Blob filters are not needed
or cannot be used, a BPB is not needed; pass 0 for bpb_length and NULL for bpb_address.
360 INTERBASE 6
isc_open_blob2()
The blob_id identifies which particular Blob is to be opened. This blob_id is set by a
sequence of DSQL function calls.
On success, isc_open_blob2() assigns a unique ID to blob_handle. Subsequent API calls
use this handle to identify the Blob against which they operate.
After a blob is opened, its data can be read by a sequence of calls to isc_get_segment().
When finished accessing the Blob, close it with isc_close_blob().
For more information about opening a Blob for retrieval and optional filtering, see
Chapter 7, “Working with Blob Data.”
Example The following fragment is excerpted from the example file, api9.c. The example program
displays job descriptions that are passed through a filter.
while ((fetch_stat = isc_dsql_fetch(status, &stmt, 1, sqlda)) == 0)
{
printf("\nJOB CODE: %5s GRADE: %d", job_code, job_grade);
printf(" COUNTRY: %-20s\n\n", job_country);
/* Open the blob with the fetched blob_id. */
isc_open_blob2(status, &DB, &trans, &blob_handle, &blob_id, 9,
bpb);
if (status[0] == 1 && status[1])
{
isc_print_status(status);
return(1);
}
}
Return Value isc_open_blob2() returns the second element of the status vector. Zero indicates success.
A nonzero value indicates an error. For InterBase errors, the first element of the status
vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_prepare_transaction()
Executes the first phase of a two-phase commit against multiple databases.
Example The following example executes the first phase of a two-phase commit and includes a
rollback in case of failure:
isc_prepare_transaction(status_vector, &trans);
if (status_vector[0] == 1 && status_vector[1])
rb_status = isc_rollback_transaction(status_vector, &trans)
else
{
isc_commit_transaction(status_vector, &trans);
if (!(status_vector[0] == 1 && status_vector[1]))
fprintf(stderr, "Commit successful.\n");
}
362 INTERBASE 6
isc_prepare_transaction2()
Return Value isc_prepare_transaction() returns the second element of the status vector. Zero
indicates success. A nonzero value indicates an error. For InterBase errors, the first
element of the status vector is set to 1, and the second element is set to an InterBase
error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_prepare_transaction2()
Performs the first phase of a two-phase commit for multi-database transactions.
Example The following example executes the first phase of a two-phase commit and includes a
rollback in case of failure:
isc_prepare_transaction2(status_vector, &trans, msg_len, msg);
if (status_vector[0] == 1 && status_vector[1])
rb_status = isc_rollback_transaction(status_vector, &trans);
Return Value isc_prepare_transaction2() returns the second element of the status vector. Zero
indicates success. A nonzero value indicates an error. For InterBase errors, the first
element of the status vector is set to 1, and the second element is set to an InterBase
error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
364 INTERBASE 6
isc_print_sqlerror()
isc_print_sqlerror()
Displays an SQLCODE value, a corresponding SQL error message, and any additional
InterBase error messages in the error status vector.
Description During the processing of DSQL API calls, SQL errors can occur. SQL errors are generally
reported in a variable called SQLCODE. DSQL calls return error information to a
user-defined error status vector like any other API call, but isc_print_sqlerror() can be
used to interpret the primary error condition as an SQL error message for direct display
on the screen. To use isc_print_sqlerror(), an application must declare both an SQLCODE
variable for holding the SQL error number, and an error status vector for holding
InterBase error information. isc_print_sqlerror() displays the SQLCODE value, a related
SQL error message, and any additional InterBase error messages in the status array.
Note Some windowing systems do not permit direct screen writes. Do not use
isc_print_sqlerror() when developing applications for these environments. Instead, use
isc_sql_interprete() and isc_interprete() to capture messages to a buffer for display.
isc_print_status()
Builds and displays error messages based on the contents of the InterBase error status
vector.
Description isc_print_status() builds all error messages based on the contents of the error status
vector, and displays them on the screen. status_vector must be declared in the program
as an array of twenty elements.
Example The following code displays error messages when an error occurs during processing:
#include <ibase.h>
ISC_STATUS status_vector[20];
. . .
if (status_vector[0] == 1 && status_vector[1])
{
isc_print_status(status_vector);
return(1);
}
Return Value isc_print_status() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
366 INTERBASE 6
isc_put_segment()
isc_put_segment()
Writes a Blob segment.
Example The following example reads a segment of one Blob and writes it to another Blob:
get_status = isc_get_segment(status, &from_blob, &seg_len, 80,
buffer);
if (status[0] == 1 && status[1])
{
isc_print_status(status);
return(1);
}
if (get_status != isc_segstr_eof)
write_status = isc_put_segment(status, &to_blob, seg_len, buffer);
if (status[0] == 1 && status[1])
{
isc_print_status(status);
return(1);
}
Return Value isc_put_segment() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
368 INTERBASE 6
isc_que_events()
isc_que_events()
Requests asynchronous notification of one of a specified group of events.
length = (short)isc_event_block(
&event_buffer,
&result_buffer,
number_of_stocks,
"DEC", "HP", "SUN");
isc_que_events(
status_vector,
&database_handle, /* Set in previous isc_attach_database(). */
&event_id,
370 INTERBASE 6
isc_que_events()
counter = 0;
while (counter < MAX_LOOP)
{
counter++;
if (!event_flag)
{
/* Do whatever other processing you want. */
;
}
else
{ event_flag = 0;
isc_event_counts(
count_array,
length,
event_buffer,
result_buffer);
if (status_vector[0] == 1 && status_vector[1])
{
isc_print_status(status_vector); /* Display error message.
*/
return(1);
}
isc_que_events(
status_vector,
&database_handle,
&event_id,
length,
event_buffer,
(isc_callback)event_function,
result_buffer);
if (status_vector[0] == 1 && status_vector[1])
{
isc_print_status(status_vector); /* Display error message.
*/
return(1);
}
} /* End of else. */
} /* End of while. */
Return Value isc_que_events() returns the second element of the status vector. Zero indicates success.
A nonzero value indicates an error. For InterBase errors, the first element of the status
vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
372 INTERBASE 6
isc_rollback_retaining( )
isc_rollback_retaining( )
Undoes changes made by a transaction and retains the transaction context after the
rollback.
Description isc_rollback_retaining() rolls back an active transaction and immediately clones itself.
This means that the function retains the transaction name, system resources associated
with the transaction, and the current state of any open cursors in the transaction.
Although the function is actually initiating a new transaction, by assigning the new
transaction the existing transaction handle it is, in effect, keeping the transaction open
after the rollback. This results in improved performance by allowing an application to
minimize the overhead of initiating additional transactions. isc_rollback_retaining()
allows you to roll back updates while keeping a cursor open.
You can initiate a rollback within the active transaction but the rollback only affects
uncommitted updates. In other words, a rollback is legal, even after the transaction
context has been passed to the cloned transaction, but, in that case, the rollback will only
affect the updates your application has made to the database since the last commit or
rollback.
To audit the rollbacks made by your calls to this function, check the first element in the
status vector to see if the call was successful. If this element contains a zero, the call was
successful.
The transaction ends when you commit or roll back without using the retention feature,
with a call to isc_commit_transaction() or isc_rollback_transaction().
Examples The following C/C++ code rolls back a transaction, prints a message, and starts a new
transaction with the same handle within the same request:
if (!isc_rollback_retaining(status, &retained_trans))
{
fprintf(stderr, "Rolled back and retained\n");
isc_print_status(status);
}
The following C/C++ code rolls back a transaction, prints a confirmation message, starts
a new transaction with the same handle within the same request, or, if the rollback fails,
prints an error message and rolls back.
isc_rollback_retaining(status, &retained_trans);
if (status[0] == 1 && status[1])
{
fprintf(stderr, "Error retaining; rolling back instead.\n");
rb_status = isc_rollback_transaction(status, &retained_trans);
}
else
{
fprintf(stderr, "Rollback retaining successful.\n");
tr_count++; /* Increments the number of recycles. */
}
Return Value isc_rollback_retaining() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
374 INTERBASE 6
isc_rollback_transaction()
isc_rollback_transaction()
Undoes changes made by a transaction, and restores the database to its state prior to the
start of the specified transaction.
Return Value isc_rollback_transaction() returns the second element of the status vector. Zero
indicates success. A nonzero value indicates an error. For InterBase errors, the first
element of the status vector is set to 1, and the second element is set to an InterBase
error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_service_attach( )
Attaches to the InterBase Services Manager facility. You must do this before using the
InterBase services functions to request execution of tasks or query information from the
Services Manager.
Description You can use this function to attach to the Services Manager on a given InterBase server.
The InterBase service must be running on that host before you can attach to the Services
Manager.
You must specify the hostname and the literal string service_mgr in the service argument.
For example, jupiter:service_mgr is the string you use to connect to the Services Manager
on host jupiter using TCP/IP as the network protocol.
You must specify a user ID and the corresponding password as part of the options in the
service parameter buffer. The Services Manager uses this user ID when performing
service tasks you request.
There are components in the InterBase Express™ package for Delphi and C++Builder
that provide a visual interface to the Services Manager. See the Developer’s Guide.
376 INTERBASE 6
isc_service_detach( )
Example See “Attaching to the Services Manager with isc_service_attach( )” on page 202 for
an example using C/C++ code.
Return Value isc_service_attach() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_service_detach( )
Terminates the attachment to the InterBase Services Manager.
Description After you have performed all tasks and retrieved all information needed from the
Services Manager, you should use this function to detach.
There are components in the InterBase Express™ package for Delphi and C++Builder
that provide a visual interface to the Services Manager. See the Developer’s Guide.
Example See “Detaching from a Services Manager with isc_service_detach( )” on page 203
for an example using C/C++ code.
Return Value isc_service_detach() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_service_query( )
Requests and retrieves information about the InterBase server to which the client is
attached.
378 INTERBASE 6
isc_service_query( )
Description Use isc_service_query() to request information from the Services Manager. You must
have an active connection to a running Services Manager, made using
isc_service_attach() (see page 376).
There are components in the InterBase Express™ package for Delphi and C++Builder
that provide a visual interface to the Services Manager. See the Developer’s Guide.
Example There are several examples of using isc_service_query( ) with C/C++ in “Querying the
Services Manager” on page 220.
Return Value isc_service_query() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_service_start( )
Performs a service task on the InterBase server to which the client is attached.
Description Use isc_service_start() to initiate a task execution by the Services Manager. You must
have an active connection to a running Services Manager, made using
isc_service_attach() (see page 376).
There are components in the InterBase Express™ package for Delphi and C++Builder
that provide a visual interface to the Services Manager. See the Developer’s Guide.
Example There are several examples of using isc_service_start( ) with C/C++ in “Invoking
service tasks with isc_service_start( )” on page 204.
Return Value isc_service_start() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
380 INTERBASE 6
isc_sqlcode( )
isc_sqlcode( )
Translates an InterBase error code in the error status vector to an SQL error code number.
Description isc_sqlcode() searches status_vector for a reported SQL error, and if it finds it, translates
the InterBase error code number into an appropriate SQL error code. Typically, this call
is used to populate a program variable (usually called SQLCODE for portability among
SQL implementations) with an SQL error number for use in an SQL error-handling
routine.
Example The following code illustrates how isc_sqlcode() might be called in a DSQL application:
#include <ibase.h>
long SQLCODE;
ISC_STATUS status_vector[20];
. . .
if (status_vector[0] == 1 && status_vector[1])
{
SQLCODE = isc_sqlcode(status_vector);
isc_print_sqlerror(SQLCODE, status_vector);
}
Return Value If successful, isc_sqlcode() returns the first valid SQL error code decoded from the
InterBase status vector.
If no valid SQL error code is found, isc_sqlcode() returns –999.
isc_sql_interprete( )
Builds an SQL error message string and stores it in a user-defined buffer.
Description Given an SQLCODE value less than zero, isc_sql_interprete() builds a corresponding SQL
error message string, and stores it in a user-defined buffer. The size of the buffer, in
bytes, must also be passed to this function.
To display an SQL error message corresponding to an SQLCODE value, use
isc_print_sqlerror() instead of this call.
382 INTERBASE 6
isc_start_multiple()
isc_start_multiple()
Begins a new transaction against multiple databases.
static char
isc_tpb_0[] = { /* Declare the first transaction parameter
buffer. */
isc_tpb_version3, /* InterBase version. */
isc_tpb_write,/* Read-write access. */
isc_tpb_consistency, /* Serializable. */
isc_tpb_wait, /* Wait on lock. */
isc_tpb_lock_write, 3, /* Reserving IDS for update. */
’I’,’D’,’S’,
isc_tpb_protected},/* Don’t allow other transactions to
write to the table. */
main()
{
db0 = db1 = 0;
384 INTERBASE 6
isc_start_multiple()
trans = 0;
teb_vec[1].dbb_ptr = &db1;
teb_vec[1].tpb_len = sizeof (isc_tpb_1);
teb_vec[1].tpb_ptr = isc_tpb_1;
if (trans)
isc_commit_transaction(isc_status, &trans);
Return Value isc_start_multiple() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_start_transaction()
Starts a new transaction against one or more databases.
386 INTERBASE 6
isc_start_transaction()
Description isc_start_transaction() starts a new transaction against one or more databases specified
as database handles.
Note If you have a variable number of databases to update, or are using a language that
does not support a variable number of arguments in a function call, use
isc_start_multiple() instead of isc_start_transaction().
A single transaction can access multiple databases. This function passes information
about each database it accesses and the conditions of access for that database in a
transaction parameter buffer (TPB). The TPB is a variably-sized vector of bytes declared
and populated by the program. It contains information describing intended transaction
behavior such as its access and lock modes.
isc_start_transaction() can start a transaction against up to 16 databases. You must pass
a database handle and a TPB for each referenced database. If you want to use defaults
for the transaction, set tpb_length to zero. In this case, tpb_vector is a NULL pointer.
Example The following program includes a call to the start transaction function:
#include <ibase.h>
long
isc_status[20], /* Status vector. */
*db, /* Database handle. */
*trans, /* Transaction handle. */
static char
isc_tpb_0[] = {
isc_tpb_version3, /* InterBase version. */
isc_tpb_write,/* Read-write access. */
isc_tpb_consistency, /* Consistency-mode transaction. */
isc_tpb_wait, /* Wait on lock. */
isc_tpb_lock_write, 3, /* Reserving IDS table for update. */
"I","D","S",
isc_tpb_protected};/* Don’t allow other transactions to
write against this table. */
main()
{
db = trans = 0;
isc_attach_database(isc_status, 0, "test.gdb", &db, 0,0);
if (db)
{
isc_start_transaction(
isc_status, &trans, 1, &db,
sizeof(isc_tpb_0), isc_tpb_0);
if (isc_status[0] == 1 && isc_status[1])
isc_print_status(isc_status);
}
if (trans)
isc_commit_transaction(isc_status, &trans);
Return Value isc_start_transaction() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
388 INTERBASE 6
isc_transaction_info()
isc_transaction_info()
Returns information about the specified named transaction.
isc_transaction_info() uses two buffers defined in the calling program: the item-list
buffer, which lists transaction items about which you want information, and a result
buffer, where the information requested is reported.
Item Description
isc_info_end End of the messages
isc_info_truncated Result buffer is too small to hold any more requested information
isc_info_error Requested information is unavailable; check the status vector for an
error code and message
TABLE 13.22 Status message return items
The function return value indicates only that InterBase accepted the request for
information. It does not mean that it understood the request or that it supplied all of the
requested information. Your application must interpret the contents of the result buffer
for details about the transaction.
isc_transaction_info(status_vector,
&tr_handle,
sizeof (tra_items), /* Length of item-list buffer. */
&tra_items, /* Address of item-list buffer. */
sizeof (tra_info), /* Length of result buffer. */
390 INTERBASE 6
isc_vax_integer()
Return Value isc_transaction_info() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
isc_vax_integer()
Reverses the byte order of an integer.
Description isc_vax_integer() reverses the byte order of an integer, specified in buffer, and returns
the newly ordered value.
A typical use for this function is to convert integer values passed into a database
parameter buffer to a format where the least significant byte must be first and the most
significant byte last. In InterBase, integer values must be represented in input parameter
buffers (for example, the DPB) and are returned in result buffers in a generic format
where the least significant byte is first, and the most significant byte last.
isc_vax_integer() is used to convert integers to and from this format.
Example The following code fragment converts a 2-byte value, stored in a character buffer that is
the result buffer returned by a function such as isc_database_info():
#include <ibase.h>
char *p;
. . .
for(p = res_buffer; *p != isc_info_end;)
{
/* Read item type of next cluster in the result buffer. */
item = *p++;
/* Read length of next value in result buffer, and convert. */
len = isc_vax_integer(p, 2);
p += len;
/* Now process the actual value, len bytes in size. */
. . .
}
isc_version()
Returns database implementation and version information.
392 INTERBASE 6
isc_version()
Description isc_version() determines the database implementation and on-disk structure (ODS)
version numbers for the database specified by db_handle. It passes this information in
two separate calls to the callback function pointed to by function_name.
function_name should point to an application function that takes two arguments: a void
pointer, user_arg, and a char pointer. Applications can pass any kind of parameter
desired in user_arg.
isc_version() makes two calls to function_name. First it determines the database
implementation number, builds a string containing the information, and calls
function_name with user_arg, and a pointer to the string containing the implementation
number in the following format:
<implementation>(<class>), version "<version>"
where:
g implementation is a text string, such as “InterBase/NT”.
g class is a text string specifying the implementation class, such as “access method”.
g version is a version identification string, such as “4.0”.
The callback function specified by function_name is free to do with this information
what it pleases.
After the callback function returns control to isc_version(), isc_version() builds a new
string containing the ODS major and minor version numbers, then calls function_name
a second time with user_arg, and a pointer to the string containing the ODS version
number in the following format:
on disk structure version <ods_major_num>.<ods_minor_num>
where:
g ods_major_num is the major ODS number. Databases with different major version
numbers have different physical layouts on disk and are incompatible with one another.
A database engine can only access databases with a particular ODS major number.
g ods_minor_num is the minor ODS number. Differences in the minor ODS number, but
not the major one indicate a non-structural change that still permits access by any
database engine that recognizes the major version number.
Examples The following code fragment calls isc_version() with a NULL callback function:
#include <ibase.h>
. . .
int ret;
. . .
ret = isc_version(&db1, NULL, "\t%s\n");
isc_wait_for_event( )
Waits synchronously until one of a specified group of events is posted.
Note The isc_wait_for_event() function was called gds_$event_wait() in InterBase 3.3.
It is therefore the only function that can’t be translated from 3.3 nomenclature to all later
versions by replacing gds_$ with isc_.
394 INTERBASE 6
isc_wait_for_event( )
Example The following program fragment illustrates a call to isc_wait_for_event() to wait for a
posting of any of the events named “DEC”, “HP”, or “SUN”.
#include <ibase.h>
#define number_of_stocks 3;
length = (short)isc_event_block(
&event_buffer,
&result_buffer,
number_of_stocks,
"DEC", "HP", "SUN");
isc_wait_for_event(
status_vector,
&database_handle,
length, /* Returned from isc_event_block(). */
event_buffer,
result_buffer);
if (status_vector[0] == 1 && status_vector[1])
{
isc_print_status(status_vector); /* Display error message. */
return(1);
}
Return Value isc_wait_for_event() returns the second element of the status vector. Zero indicates
success. A nonzero value indicates an error. For InterBase errors, the first element of the
status vector is set to 1, and the second element is set to an InterBase error code.
To check for an InterBase error, examine the first two elements of the status vector
directly. For more information about examining the status vector, see Chapter 10,
“Handling Error Conditions.”
396 INTERBASE 6
APPENDIX
InterBase Document
AppendixA
A
Conventions
Book Description
Operations Guide Provides an introduction to InterBase and an explanation of tools and
procedures for performing administrative tasks on databases and
database servers; also includes full reference on InterBase utilities,
including isql, gbak, gfix, and others
Data Definition Guide Explains how to create, alter, and delete database objects using the SQL
language
Developer’s Guide Provides both reference and task-oriented material for users of the
Borland RAD tools (Delphi, C++ Builder, and JBuilder); includes chapters
on writing UDFs, driver configuration, developing embedded installation
applications, and using the new InterBase Data Access Components
Language Reference Describes the SQL language syntax and usage; includes references for
procedure and trigger language, InterBase keywords, functions in the
InterBase UDF library, error codes, character sets, and the system tables
Embedded SQL Guide (formerly called the Programmer’s Guide) Describes how to write
embedded SQL database applications in a host language, precompiled
through gpre
API Guide Explains how to write database applications using the InterBase API
TABLE A.1 Books in the InterBase 6 documentation set
398 INTERBASE 6
PRINTING CONVENTIONS
Printing conventions
The InterBase documentation set uses various typographic conventions to identify objects
and syntactic elements.
The following table lists typographic conventions used in text, and provides examples of
their use:
Conventio
n Purpose Example
UPPERCASE SQL keywords, SQL functions, and names of • the SELECT statement retrieves data from the CITY column
all database objects such as tables, columns, in the CITIES table
indexes, and stored procedures • can be used in CHAR, VARCHAR, and BLOB text columns
• the CAST() function
italic New terms, emphasized words, all elements • isc_decode_date()
from host languages, and all user-supplied • the host variable, segment_length
items • contains six variables, or data members
bold File names, menu picks, and all commands • gbak, isql, gsec. gfix
that are entered at a system prompt, • specify the gpre -sqlda old switch
including their switches, arguments, and • a script, ib_udf.sql, in the examples subdirectory
parameters
• the employee.gdb database; the employee database
• the Session | Advanced Settings command
TABLE A.2 Text conventions
Syntax conventions
The following table lists the conventions used in syntax statements and sample code, and
provides examples of their use:
italic User-supplied parameters that cannot be •CREATE TRIGGER name FOR table;
broken into smaller units •ALTER EXCEPTION name 'message'
400 INTERBASE 6
APPENDIX
Data Structures
AppendixB
B
This appendix documents the data structures, compile-time constants, parameter buffers,
and information buffers utilized in InterBase API applications.
This information also appears throughout the rest of this API Guide, but is consolidated
here as a convenience. See other sections of this manual for more information.
All the structures and compile-time constants mentioned are defined in the ibase.h header
file. Items are documented alphabetically, as follows:
g Array descriptor
g Blob descriptor
g Blob information item-list buffer and result buffer
g Blob parameter buffer
g Database information request buffer and result buffer
g Database parameter buffer
g SQL datatype macro constants
g Status vector
g Transaction parameter buffer
g XSQLDA and XSQLVAR structures
Array descriptor
An array descriptor ISC_ARRAY_DESC is a structure defined in the ibase.h header file as:
typedef struct {
unsigned char array_desc_dtype;
char array_desc_scale;
unsigned short array_desc_length;
char array_desc_field_name [32];
char array_desc_relation_name [32];
short array_desc_dimensions;
short array_desc_flags;
ISC_ARRAY_BOUND array_desc_bounds [16];
} ISC_ARRAY_DESC;
Field Description
array_desc_dtype Datatype (see below)
array_desc_scale Scale for numeric datatypes
array_desc_length Length in bytes of each array element
array_desc_field_name NULL-terminated column name
array_desc_relation_name NULL-terminated relation name
array_desc_dimensions Number of array dimensions
array_desc_flags Specifies whether array is to be accessed in row- major or column-major
order
• 0: row-major
• 1: column-major
array_desc_bounds Lower and upper bounds for each dimension
TABLE B.1 Array descriptor fields
402 INTERBASE 6
DATATYPES FOR ARRAY DESCRIPTORS
array_desc_dtype
value Corresponding InterBase datatype
blr_text CHAR
blr_text2 CHAR
blr_short SMALLINT
blr_long INTEGER
blr_float FLOAT
blr_sql_date DATE
blr_sql_time TIME
blr_timestamp TIMESTAMP
blr_varying VARCHAR
blr_varying2 VARCHAR
Blob descriptor
A Blob descriptor is defined as:
typedef struct {
short blob_desc_subtype;
short blob_desc_charset;
short blob_desc_segment_size;
unsigned char blob_desc_field_name [32];
unsigned char blob_desc_relation_name [32];
} ISC_BLOB_DESC;
Field Description
blob_desc_subtype Type of Blob data
0: unstructured
1: TEXT
negative integer between –1 and –32678: user-defined subtype
blob_desc_charset Character set (see below)
blob_desc_segment_size Segment size
blob_desc_field_name NULL-terminated column name
Character sets
InterBase supports a number of character sets. For a list of the character sets supported,
and the character set value that must be entered in the blob_desc_charset field of a Blob
descriptor, see the Data Definition Guide.
404 INTERBASE 6
BLOB DESCRIPTOR
4 Item-list buffer
The item-list buffer is a byte vector into which is placed a sequence of byte values, one
per requested item of information. Each byte is an item type, specifying the kind of
information desired. Compile-time constants for all item types are defined in ibase.h:
#define isc_info_blob_num_segments 4
#define isc_info_blob_max_segment 5
#define isc_info_blob_total_length 6
#define isc_info_blob_type 7
4 Result buffer
The result buffer is a byte vector in which InterBase returns a series of clusters of
information, one per item requested. Each cluster consists of three parts:
1. A one-byte item type. Each is the same as one of the item types in the item-list
buffer.
2. A 2-byte number specifying the number of bytes that follow in the remainder
of the cluster.
3. A value, stored in a variable number of bytes, whose interpretation depends
on the item type.
A calling program is responsible for interpreting the contents of the result buffer and for
deciphering each cluster as appropriate.
The clusters returned to the result buffer are not aligned. Furthermore, all numbers are
represented in a generic format, with the least significant byte first, and the most
significant byte last. Signed numbers have the sign in the last byte. Convert the numbers
to a datatype native to your system, if necessary, before interpreting them. The API call,
isc_vax_integer(), can be used to perform the conversion.
Item Description
isc_info_end End of the messages
isc_info_truncated Result buffer is too small to hold any more requested information
isc_info_error Requested information is unavailable. Check the status vector for an
error code and message
TABLE B.5 Status message return items
406 INTERBASE 6
DATABASE INFORMATION REQUEST BUFFER AND RESULT BUFFER
1. A one-byte parameter type. There are compile-time constants defined for all
the parameter types (for example, isc_bpb_target_type).
2. A one-byte number specifying the number of bytes that follow in the
remainder of the cluster.
3. A variable number of bytes, whose interpretation depends on the parameter
type.
All numbers in the Blob parameter buffer must be represented in a generic format, with
the least significant byte first, and the most significant byte last. Signed numbers should
have the sign in the last byte. The API function isc_vax_integer() can be used to reverse
the byte order of a number. For more information about isc_vax_integer(), see
“isc_vax_integer()” on page 391 of Chapter 13, “API Function Reference.”
The following table lists the parameter types and their meaning. For lists of the possible
subtypes and character sets, see “Blob descriptor” on page 403.
Request buffer
The request buffer is a byte vector into which is placed a sequence of byte values, one
per requested item of information. Each byte is an item type, specifying the kind of
information desired. Compile-time constants for all item types are defined in ibase.h and
shown below.
Result buffer
The result buffer is a byte vector in which InterBase returns a series of clusters of
information, one per item requested. Each cluster consists of three parts:
1. A one-byte item return type. These are the same as the item types specified
in the request buffer.
2. A two-byte number specifying the number of bytes that follow in the
remainder of the cluster.
3. A value, stored in a variable number of bytes, whose interpretation (as a
number or as a string of characters, for example) depends on the item return
type.
A calling program is responsible for interpreting the contents of the result buffer and for
deciphering each cluster as appropriate. In many cases, the value simply contains a
number or a string (sequence of characters). But in other cases, the value is a number of
bytes whose interpretation depends on the item return type.
The clusters returned to the result buffer are not aligned. Furthermore, all numbers are
represented in a generic format, with the least significant byte first, and the most
significant byte last. Signed numbers have the sign in the last byte. Convert the numbers
to a datatype native to your system, if necessary, before interpreting them. The API call,
isc_vax_integer(), can be used to perform the conversion.
408 INTERBASE 6
DATABASE INFORMATION REQUEST BUFFER AND RESULT BUFFER
Item Description
isc_info_end End of the messages
isc_info_truncated Result buffer is too small to hold any more requested information
isc_info_error Requested information is unavailable; check the status vector for an error
code and message
TABLE B.7 Status message return items
4 Database characteristics
Several items are provided for determining database characteristics, such as its size and
major and minor ODS version numbers. The following table lists the request buffer items
that can be passed, and the information returned in the result buffer for each item type:
410 INTERBASE 6
DATABASE INFORMATION REQUEST BUFFER AND RESULT BUFFER
4 Environmental characteristics
Several items are provided for determining environmental characteristics, such as the
amount of memory currently in use, or the number of database cache buffers currently
allocated. These items are described in the following table:
4 Performance statistics
There are four items providing performance statistics for a database. These statistics
accumulate for a database from the moment it is first attached by any process until the
last remaining process detaches from the database. A program requesting this
information, therefore, sees information pertaining to its own attachment and all other
attachments.
For example, the value returned for isc_info_reads is the number of reads since the
current database was first attached: it is an aggregate of all reads done by all attached
processes, rather than the number of reads done for the calling program since it attached
to the database.
412 INTERBASE 6
DATABASE INFORMATION REQUEST BUFFER AND RESULT BUFFER
The items providing performance statistics are summarized in the following table:
The following table describes the items which return count values for operations on the
database:
414 INTERBASE 6
DATABASE INFORMATION REQUEST BUFFER AND RESULT BUFFER
The following table lists DPB parameters in alphabetical order. For each parameter, it lists
its purpose, the length, in bytes, of any values passed with the parameter, and the value
to pass:
416 INTERBASE 6
DATABASE INFORMATION REQUEST BUFFER AND RESULT BUFFER
C datatype or sqlind
SQL datatype Macro expression typedef used?
Array SQL_ARRAY ISC_QUAD No
Array SQL_ARRAY + 1 ISC_QUAD Yes
Blob SQL_BLOB ISC_QUAD No
Blob SQL_BLOB + 1 ISC_QUAD Yes
CHAR SQL_TEXT char[ ] No
CHAR SQL_TEXT + 1 char[ ] Yes
DATE SQL_DATE ISC_DATE No
DATE SQL_DATE + 1 ISC_DATE Yes
DECIMAL SQL_SHORT, SQL_LONG, SQL_DOUBLE, int, long, double, or No
or SQL_INT64 ISC_INT64
418 INTERBASE 6
SQL DATATYPE MACRO CONSTANTS
C datatype or sqlind
SQL datatype Macro expression typedef used?
NUMERIC SQL_SHORT, SQL_LONG, SQL_DOUBLE, int, long, double, or No
or SQL_INT64 ISC_INT64
DECIMAL and NUMERIC datatypes are stored internally as SMALLINT, INTEGER, DOUBLE
PRECISION, or 64-bit integer datatypes. To specify the correct macro expression to provide
for a DECIMAL or NUMERIC column, use isql to examine the column definition in the table
to see how InterBase is storing column data, then choose a corresponding macro
expression.
The datatype information for a parameter or select-list item is contained in the sqltype
field of the XSQLVAR structure. The value contained in sqltype provides two pieces of
information:
g The datatype of the parameter or select-list item.
g Whether sqlind is used to indicate NULL values. If sqlind is used, its value specifies
whether the parameter or select-list item is NULL (-1), or not NULL (0).
For example, if sqltype equals SQL_TEXT, the parameter or select-list item is a CHAR that
does not use sqlind to check for a NULL value (because, in theory, NULL values are not
allowed for it). If sqltype equals SQL_TEXT + 1, then sqlind can be checked to see if the
parameter or select-list item is NULL.
The C language expression, sqltype & 1, provides a useful test of whether a parameter or
select-list item can contain a NULL. The expression evaluates to 0 if the parameter or
select-list item cannot contain a NULL, and 1 if the parameter or select-list item can
contain a NULL.
Status vector
Most API functions return status information that indicates success or failure. Status
information is reported in an error status vector, declared in applications as an array of
twenty long integers, using the following syntax:
#include <ibase.h>
. . .
ISC_STATUS status_vector[20];
If you plan to write your own routines instead of the InterBase error-handling routines to
read and react to the contents of the status vector, you need to know how to interpret it.
InterBase stores error information in the status vector in clusters of two or three longs.
The first cluster in the status vector always indicates the primary cause of the error.
Subsequent clusters may contain supporting information about the error, for example,
strings or numbers for display in an associated error message. The actual number of
clusters used to report supporting information varies from error to error.
In many cases, additional errors may be reported in the status vector. Additional errors
are reported immediately following the first error and its supporting information, if any.
The first cluster for each additional error message identifies the error. Subsequent clusters
may contain supporting information about the error.
420 INTERBASE 6
MEANING OF THE FIRST LONG IN A CLUSTER
The following table lists possible values for the first long in any cluster in the status
vector. Note that the first cluster in the status vector can only contain values of 0, 1, or
greater than 4:
Longword
Value in cluster Meaning
0 — End of error information in the status vector
1 2 Second long is an InterBase error code
2 2 Second long is the address of string used as a replaceable parameter in a
generic InterBase error message
3 3 Second long is the length, in bytes, of a variable length string provided by the
operating system (most often this string is a file name); third long is the
address of the string
4 2 Second long is a number used as a replaceable parameter in a generic
InterBase error message
5 2 Second long is the address of an error message string requiring no further
processing before display
6 2 Second long is a VAX/VMS error code
7 2 Second long is a UNIX error code
8 2 Second long is an Apollo Domain error code
9 2 Second long is an MS-DOS or OS/2 error code
10 2 Second long is an HP MPE/XL error code
11 2 Second long is an HP MPE/XL IPC error code
12 2 Second long is a NeXT/Mach error code
NOTE As InterBase is adapted to run on other hardware and software platforms, additional numeric
descriptors for specific platform and operating system error codes may be added to the end of this list.
TABLE B.15 Interpretation of status vector clusters
The following table lists the ibase.h #define equivalents of each numeric descriptor:
422 INTERBASE 6
TRANSACTION PARAMETER BUFFER
Parameter Description
isc_tpb_version3 InterBase version 3 transaction
isc_tpb_consistency Table-locking transaction model
isc_tpb_concurrency High throughput, high concurrency transaction with acceptable consistency;
use of this parameter takes full advantage of the InterBase multi-generational
transaction model [Default]
isc_tpb_shared Concurrent, shared access of a specified table among all transactions.; use in
conjunction with isc_tpb_lock_read and isc_tpb_lock_write to establish the
lock option [Default]
isc_tpb_protected Concurrent, restricted access of a specified table; use in conjunction with
isc_tpb_lock_read and isc_tpb_lock_write to establish the lock option
isc_tpb_wait Lock resolution specifies that the transaction is to wait until locked resources
are released before retrying an operation [Default]
isc_tpb_nowait Lock resolution specifies that the transaction is not to wait for locks to be
released, but instead, a lock conflict error should be returned immediately
isc_tpb_read Access mode of read-only that allows a transaction only to select data from
tables
isc_tpb_write Access mode of read-write that allows a transaction to select, insert, update,
and delete table data [Default]
isc_tpb_lock_read Read-only access of a specified table; use in conjunction with isc_tpb_shared,
isc_tpb_protected, and isc_tpb_exclusive to establish the lock option
isc_tpb_lock_write Read-write access of a specified table; use in conjunction with isc_tpb_shared,
isc_tpb_protected, and isc_tpb_exclusive to establish the lock option [Default]
TABLE B.17 TPB constants
Parameter Description
isc_tpb_read_committed High throughput, high concurrency transaction that can read changes
committed by other concurrent transactions; use of this parameter takes full
advantage of the InterBase multi-generational transaction model
isc_tpb_rec_version Enables an isc_tpb_read_committed transaction to read the most recently
committed version of a record even if other, uncommitted versions are
pending.
isc_tpb_no_rec_version Enables an isc_tpb_read_committed transaction to read only the latest
committed version of a record
If an uncommitted version of a record is pending and isc_tpb_wait is also
specified, then the transaction waits for the pending record to be committed
or rolled back before proceeding; otherwise, a lock conflict error is reported at
once
TABLE B.17 TPB constants (continued)
424 INTERBASE 6
XSQLDA AND XSQLVAR
g Table reservation optionally describes an access method and lock resolution for a
specified table that the transaction accesses. When table reservation is used, tables are
reserved for the specified access when the transaction is started, rather than when the
transaction actually accesses the table. Valid reservations are:
isc_tpb_shared, isc_tpb_lock_write
isc_tpb_shared, isc_tpb_lock_read
isc_tpb_protected, isc_tpb_lock_write
isc_tpb_protected, isc_tpb_lock_read
Syntax
One field in the XSQLDA, sqlvar, is an XSQLVAR structure. The sqlvar is especially important
because one XSQLVAR must be defined for each input parameter or column returned.
Applications do not declare instances of the XSQLVAR ahead of time, but must, instead,
dynamically allocate storage for the proper number of XSQLVAR structures required for
each DSQL statement before it is executed, then deallocate it, as appropriate, after
statement execution.
The following figure illustrates the relationship between the XSQLDA and the XSQLVAR.
short version
char sqldaid[8]
ISC_LONG sqldabc
short sqln
short sqld
An input XSQLDA consists of a single XSQLDA structure, and one XSQLVAR structure for each
input parameter. An output XSQLDA also consists of one XSQLDA structure and one XSQLVAR
structure for each data item returned by the statement.
426 INTERBASE 6
XSQLDA AND XSQLVAR
428 INTERBASE 6
XSQLDA AND XSQLVAR
430 INTERBASE 6
Index
API GUIDE i
multi-dimensional 150, 151 deleting 130
dimensions, range 150 DSQL applications and 83, 120, 122–124,
nested 150 127
overview 150–151 fetching 124
processing 28 filtering 142–147, 279
reading data 154–159 processing 27, 287, 290
creating data buffers 158 reading 121–126, 134
retrieving data 151, 154, 156, 254 BLOB filters and 142
selected rows 158 retrieving information about 131–134, 282
row-major order, specifying 260, 263, 274 defaults 279
subscripts 150 selecting 121–124
subsets status messagess 132
retrieving 151 storing 120, 128, 290
writing to 151 support 119
updating 160–166 translating 136, 294
asynchronous events 189, 192 updating 126, 127–128, 367
canceling notification 197, 289 BLOB datatype
requesting notification 369 arrays and 150
asynchronous traps 192–193 NULL values 123, 126, 130
creating 193 user-defined 119
attaching to a database 32 BLOB descriptors 28, 134–135
attaching to databases 49–51, 80, 276 populating 135, 279
See also connecting to databases structure, defined 134
DPBs and 44 BLOB filter function
optional entries 24 action macro definitions 141
releasing system resources 305 defining 137
retrieving information about 51–57, 297 input/output fields 139
temporarily 306 BLOB filters 28, 134, 136–147
Windows clients 32, 34 control structure, defined 139
automatic recovery functions 364 external 136, 136–142
declaring 137
writing 137–142
B
invoking 142
binary data 119 NetWare servers and 136
binary file types, supported 119 opening BLOBs 146, 288, 360
binary large objects See BLOB specifying 294
bitmapped images 119 user-defined 136
BLOB (defined) 118 BLOB handles 129
BLOB API functions 118, 141 allocating 287
BLOB columns BLOB IDs 120
creating 128–130 creating 129
writing data to 123, 134 declaring 129
BLOB filters and 142 resetting 126
BLOB data 117, 120–131 BLOB parameter buffers 142–146
changing 126 generating 281
creating 288, 294
ii INTERBASE 6
numeric formats 145 converting
parameter types 145 SQL statements to 84, 96
BLOB segments 135 CHARACTER VARYING datatype
allocating 129 DSQL applications and 93
defined 120 client applications See SQL client applications;
reading 353 Windows clients
retrieving 125 client libraries 34
size 284 CLOSE 84
writing 367 closing
BLOB subtypes 119 databases 74
filtering 360 coercing datatypes (XSQLDAs) 94
retrieving 279, 284 column names
setting 286 storing 152
Borland C/C++ See C language column-major order
BPBs See BLOB parameter buffers specifying 260, 263, 274
buffers 158, 161 columns
BLOB filters 142 arrays and 150, 154
capturing error messages 174, 177 DSQL applications 312
database attachments 44, 51 retrieving information about 312
reinitializing event 196 commits 74, 76, 292
transactions 62 See also transactions
byte order, reversing 170 delaying 77
executing 292, 362, 363
retaining context 291
C
compiling 30
C language connecting to databases 42–51
converting dates 168–170 See also attaching to databases
directives 24, 27, 29 constants
error handling 180 item types (BLOBs) 131
event notification 190 converting
predefined constants dates 168–170
item types (BLOBs) 131 CREATE DATABASE 82
predefined macros 90 DSQL applications 326
action messages (BLOBs) 141 cursors
datatypes (XSQLDAs) 90–95 closing 334
informational (SQL) 113 declaring 104, 111
time structures 168 DSQL applications 334, 339
CAD files 119 naming 339
changes opening 339
undoing 375
See also rollbacks
character sets D
BLOB data and 135, 143 data
retrieving current 279, 284 binary 119
setting 286 corrupted 74
character strings fetching 124, 158
iv INTERBASE 6
DSQL applications 27, 79 clusters 178
arrays and 83, 153, 256 declaring 172
BLOB processing 83, 120, 122–124, 127 numeric descriptors 179–181
closing cursors 334 numeric values 182
declaring cursors 104, 111 parsing 178–187
defining cursors 339 error-handling API functions 29, 171
error handling 176–178 DSQL applications 176–178
extended descriptor areas See XSQLDAs error-handling routines 74, 181
fetching data 330 SQL 381, 382
queries 101–113 errors 178, 375
retrieving information about 314 run-time 171
SELECT statements 312 transactions 74
SQL statements 83–85 event buffer, reinitializing 196
DSQL statements event parameter buffers 188
executing 317, 321, 325, 328 allocating 347
repeatedly 336 comparing event counts 349
handles creating 190
allocating 308, 310 events 187
freeing 334 asynchronous 189, 192
input parameters 314 canceling notification 197, 289
retrieving information about 342 requesting notification 369
DSQL_close option 334 posting 349
DSQL_drop option 335 processing 29, 192–193
dynamic link libraries See DLLs retrieving 196
dynamic SQL See DSQL synchronous 189, 394
transaction control 189
waiting on 191, 193
E
example programs 40
environment variables 33–34 EXECUTE 84
environments EXECUTE IMMEDIATE 84
PCs 32 EXECUTE PROCEDURE
retrieving information about 54 DSQL applications 312, 321, 326
EPBs See event parameter buffers extended SQL descriptor areas See XSQLDAs
error codes 172, 181 external BLOB filters See BLOB filters
examining status vector 178–182
system 182
translating 176, 381 F
error messages 172 FETCH 84
See also SQL error messages fetching data 124, 158
addresses 181, 182 See also retrieving data
building 355 DSQL applications 330
displaying 173, 174, 176, 366 FILE structure 42
DSQL applications 176–178 file types
error status array 29 BLOB data 119
error status vectors 29 filtering BLOB data 142–147, 279
checking 172 See also BLOB filters
API GUIDE v
formatting DPBs and 44
error messages 174 isc_blob_default_desc() 279
function prototypes 36 isc_blob_gen_bpb() 143, 281
isc_blob_info() 131–134, 282
isc_blob_lookup_desc() 284
G
isc_blob_set_desc() 286
GDS.DLL 40 isc_cancel_blob() 131, 287
isc_cancel_events() 197, 289
H isc_close_blob() 290
handles See database handles; transaction handles isc_commit_retaining() 75, 291
header files See ibase.h isc_commit_transaction() 74, 76, 292
host names, specifying 34 isc_create_blob2() 129, 146, 294
ISC_DATABASE environment variable 34
isc_database_info() 51, 56, 297
I isc_db_handle type 43
ibase.h 24, 25 isc_decode_date() 169, 299, 300, 301
BLOB descriptors 28 isc_detach_database() 57, 305
errors 29 isc_drop_database() 58, 306
XSQLDA structures 27 isc_dsql_allocate_statement() 97, 308
include files See ibase.h isc_dsql_allocate_statement2() 310
indeterminate datatypes 119 isc_dsql_describe() 87, 312
information item macros (SQL) 113 isc_dsql_describe_bind() 314
informational API functions 51, 131, 196 isc_dsql_exec_immed2() 328
initializing isc_dsql_execute() 97, 317
array descriptors 273 isc_dsql_execute_immediate() 96, 325
array IDs 164 isc_dsql_execute2() 321
BLOB handles 129 isc_dsql_fetch() 124, 158, 330
BLOB IDs 129 SELECT statements and 331
database handles 25, 43 isc_dsql_prepare() 87, 97, 336
transaction handles 25, 61 isc_dsql_sql_info() and 342
input descriptors See XSQLDAs isc_dsql_set_cursor_name() 339
input fields isc_dsql_sql_info() 113–149, 342
BLOB filters 140 isc_encode_date() 170, 344, 345, 346
input parameters isc_event_block() 190, 347
DSQL statements 314 isc_event_counts() 196–197, 349
INSERT isc_expand_dpb() 48, 351
arrays 162, 165 ISC_EXPORT keyword 27
BLOB data 120, 127 isc_get_segment() 125, 353
ISC_ARRAY_BOUND structure 151 BLOB filters and 140
ISC_ARRAY_DESC structure 151 isc_info_truncated value 131
isc_array_get_slice() 254 isc_interprete() 174, 355
isc_array_lookup_bounds() 152, 157, 161, 259 isc_open_blob2() 146, 360
isc_array_lookup_desc() 152, 263 ISC_PASSWORD environment variable 34
isc_array_put_slice() 160, 164, 266 isc_prepare_transaction() 76, 362
isc_array_set_desc() 152, 273 isc_prepare_transaction2() 77, 363
isc_attach_database() 49, 276
vi INTERBASE 6
isc_print_sqlerror() 176, 365 Microsoft C/C++ See C language
isc_print_status() 173, 366 Microsoft Windows See Windows
isc_put_segment() 129, 367 monitoring performance 298
BLOB filters and 139 multi-dimensional arrays 150, 151
isc_que_events() 192–195, 369 dimensions, range 150
isc_rollback_transaction() 74, 77, 375 multiple databases
isc_sql_interprete() 177–178, 382 attaching to 80
isc_sqlcode() 176, 381 transactions and 71, 76, 362, 363, 383
isc_start_multiple() 71, 383
isc_start_transaction() vs. 387
N
isc_start_transaction() 69, 70, 386
ISC_STATUS pointer 173 NCHAR VARYING datatype
isc_tr_handle type 61 DSQL applications and 93
isc_transaction_info() 389 nested arrays 150
ISC_USER environment variable 34 NetWare servers
isc_vax_integer() 170, 391 BLOB filters and 136
isc_version() 392 user names, returning 54
isc_wait_for_event() 191–192, 394 network DLLs 40
isolation level parameter 65, 67 NULL pointers 69
restrictive 66 NULL status 90
item type constants (BLOBs) 131 NULL values
item-list buffer 131 arrays and 153, 163, 164, 166
See also isc_blob_info() BLOB columns 123, 126, 130
BLOB handles 287
extended descriptor areas 92, 94
L numbers 170
libraries alignment addresses 95
BLOB filtering routines 136 byte ordering 170
dynamic link See DLLs processing in XSQLDAs 93, 94
limbo transactions 362 NUMERIC datatype
linking 30 DSQL applications and 93
lock resolution parameter 67 numeric values See values
log files 177
O
M ODS See on-disk structure
macros on-disk structure
action messages (BLOBs) 141 retrieving information about 53
ALIGN 95 OPEN 84
datatypes (XSQLDAs) 90–95 opening
informational (SQL) 113 BLOBs 146, 288, 360
XSQLDA_LENGTH 90 cursors 339
memory output
allocating 90 error messages 173, 174, 176, 365, 366
retrieving information about 54 output descriptors See XSQLDAs
messages See error messages; status messages output fields
viii INTERBASE 6
singleton SELECTs T
DSQL applications 329 table names
sound files, supported 119 storing 152
SQL clients 32 tables
SQL descriptor areas (extended) See XSQLDAs accessing 68–69
SQL error messages 176–178 temporary databases 306
See also SQLCODE variable text
building 381, 382 BLOB type and 119
displaying 176, 365 text files, supported 119
SQL error-handling routines 381, 382 time structures 168
SQL statements TPBs See transaction parameter buffers
converting to character strings 84, 96 transaction handles 61–62
creating 98, 102, 108 assigning at run time 81
DSQL applications and 83–85 declaring 25, 61
parameters, supplying values 89, 90, defined 25
98, 106 initializing 25, 61
executing 98, 101, 104, 106, 111, 113 transaction IDs
non-query statements and 96–101 tracking 389
processing 98–101, 106–113 transaction parameter buffers 26, 59
with no parameters 96–97, 101–106 constants 63
retrieving select-list items 104 creating 62–73
selecting BLOB data 121–124 default 69
SQLCODE variable numeric formats 170
DSQL applications 176 transactions 59
return values 365 access modes 65, 67
statements accessing tables 68–69
retrieving 113–149, 342 committing 74, 76, 77, 292
status information 90, 172 executing two-phase commits 292,
status messages 362, 363
BLOB data 132 retaining context 291
transactions 390 ending 73
status vectors See error status vectors events and 189
storing isolation levels 65–67
BLOB data 120, 128 limbo 362
data 150, 163, 165 locking conflicts 67
string addresses multiple databases 71, 76, 362, 363, 383
error messages 181, 182 optimizing 75
strings See character strings referencing 25
subscripts (arrays) 150 retrieving information about 389
sweeping databases rolling back 77, 375
retrieving information about 54 simultaneous 66, 68
synchronous events 189 specifying attributes 62–73
requesting notification 394 starting 25, 60, 383, 386
system crashes 364 status messages 390
system error codes 182 transaction existence blocks (TEBs) 71
API GUIDE ix
transaction parameter blocks (TPBs) 59–72 defining datatypes 34, 36
traps 192–193 event notification 191
See also events setting default directories 34
Windows clients
attaching 32, 34
U
establishing program parameters 33
unknown datatypes 119 security 34
unknown statements 113, 342 writing data
UPDATE to arrays 160–166, 266
arrays 162–166 to BLOBs 123, 134
BLOB data 120, 127–128 BLOB filters and 142
DSQL applications 340
updating
arrays 160–166 X
BLOB data 126, 127–128, 367 XSQLDA_LENGTH macro 90
user names 24 XSQLDAs 85–95
overriding 34 See also XSQLVAR structure
retrieving information about 54 address alignment 95
supplying at run time 351 coercing datatypes 94
Windows clients 32, 34 numbers 94
user-defined BLOB filters 136 variable-length data 94
user-defined types declaring 85
BLOB data 119 fields 87
input descriptors 85, 87, 89
allocating 90
V
arrays 162
value parameters creating 98, 106
SQL statements 85 output descriptors 85, 87, 89
values allocating 90
See also NULL values creating 101, 107
numeric descriptors 182 resizing 337
VARCHAR datatype retrieving NULL values 90, 92
DSQL applications and 93, 94 select-list items and 101, 103, 107
variable-length data, processing 93, 94 arrays 154–155, 158
vector-graphic files, supported 119 BLOB data 121
version numbers setting NULL values 94
databases 52, 392 specifying datatypes 90–95
on-disk structure 53 numbers 93
transaction processing 65 variable-length data 93, 94
video files, supported 119 structures 27, 85
video segments 119 XSQLVAR structure 89, 100
views allocating 87
arrays and 153 arrays 156
BLOB data 122, 128
W datatypes 92
Windows applications 26 defined 85
x INTERBASE 6
fields 88
setting up select-list items 103
API GUIDE xi
xii INTERBASE 6