DB Access Module for Sybase User’s Guide : Chapter 2 Technical Information : Open SQL and Sybase Open Client Client-Library : Open SQL Examples
Open SQL Examples
This section provides some Open SQL examples.
An Open SQL Insert Example
This example shows how to use the Open SQL class RWDBOSql in a Sybase Client-Library insert operation. The insert is done on a foo table with an int column and a float column.
 
#define NUMBER_OF_ROWS 10
 
RWDBOSql openSql;
 
RWDBTBuffer<int> intBuffer(NUMBER_OF_ROWS); //1
RWDBTBuffer<float> floatBuffer(NUMBER_OF_ROWS);
 
FillupValues(intBuffer, floatBuffer, NUMBER_OF_ROWS); //2
 
RWCString sybaseSyntaxSql("INSERT INTO foo VALUES(@c1, @c2)"); //3
openSql.statement(sybaseSyntaxSql); //4
 
openSql << intBuffer; //5
openSql << floatBuffer;
 
openSql.execute(conn); //6
 
if( !openSql.isValid() ) //7
cout << “Insert Into Foo Has Failed” << endl;
//1 These two lines create an int buffer and a float buffer, each of size 10.
//2 Fills the buffers with values using a predefined function.
//3 Declares a Sybase-specific SQL syntax for insertion into a foo table.
//4 Associates the SQL with the RWDBOSql object.
//5 These two lines associate the buffer with the RWDBOSql object.
//6 Executes the SQL statement.
//7 Checks the validity of the execution. If an error handler is associated with the connection or with the RWDBOSql object, the error handler is invoked if the operation fails. When error handlers are associated, explicit error checking is unnecessary.
Open SQL Query Examples
These examples illustrate how an RWDBOSql object can be used to execute a SELECT query and retrieve its results. The SELECT query is executed on an employee table emp and retrieves all columns of the table for employees in a particular department. The example assumes an error handler is associated with the connection in use, and doesn't check for any errors after calls to the RWDBOSql object.
The structure of the table emp is:
 
empno INT NOT NULL
ename VARCHAR(10) NOT NULL
posn VARCHAR(9) NOT NULL
mgr INT NULL
sal NUMERIC(7,2) NOT NULL
dept INT NOT NULL
The first example assumes awareness of the structure of table emp, and hence the schema of the result set returned by the query.
 
RWDBOSql openSql("SELECT * FROM emp WHERE dept = @dept", RWDBOSql::Query); //1
RWDBTBuffer<int> queryDeptBuff; //2
queryDeptBuff[0] = 3; //3
 
openSql << queryDeptBuff; //4
openSql.execute(cn); //5
 
const size_t ROWS_TO_FETCH = 5; //6
 
RWDBTBuffer<int> empnoBuff(ROWS_TO_FETCH), mgrBuff(ROWS_TO_FETCH),
deptBuff(ROWS_TO_FETCH);
RWDBTBuffer<RWCString> enameBuff(ROWS_TO_FETCH), posnBuff(ROWS_TO_FETCH);
RWDBTBuffer<RWDecimalPortable> salBuff(ROWS_TO_FETCH); //7
 
openSql[0] >> empnoBuff >> enameBuff >> posnBuff >>
mgrBuff >> salBuff >> deptBuff; //8
 
long rowsFetched = 0;
while ((rowsFetched = openSql.fetch().rowsFetched()) > 0) { //9
for (size_t i = 0; i < rowsFetched; ++i) {
cout << empnoBuff[i] << "\t" << enameBuff[i] << "\t"
<< posnBuff[i] << "\t"; //10
if (mgrBuff.isNull(i)) { //11
cout << "NULL";
}
else {
cout << mgrBuff[i];
}
cout << "\t" << salBuff[i] << "\t" << deptBuff[i] << endl;
}
}
//1 Creates an RWDBOSql object with the supplied SQL query and the hint RWDBOSql::Query indicating that the SQL is a SELECT statement. @dept in the SQL statement is a placeholder for the department number from which employees are to be selected. The placeholder needs to be bound before executing the RWDBOSql.
//2 Creates an RWDBTBuffer object to bind to the placeholder. This object is templatized on type int, as the dept column is of server type INT. The buffer will have a single entry of type int.
//3 The single entry from the buffer created in //2 is accessed using in the index operator and assigned the department number, the records of which will be queried.
//4 Binds the buffer to the RWDBOSql object. The SQL query has only one placeholder, hence only one buffer needs to be bound. The RWDBOSql object is now ready for execution.
//5 Executes the RWDBOSql object on a supplied RWDBConnection object.
//6 Defines a constant for the number of rows to fetch at a time from the query result set.
//7 Creates RWDBTBuffer objects to be used in fetching the query result set, with one object per column of the result set. The objects are templatized on the expected server types of the result columns as mapped to SourcePro types. (See “Datatypes” for type mapping detail.) Each buffer is created with the number of entries equal to the number of rows to be fetched for each call.
//8 Binds the output buffers to the first RWDBMultiRow object in the RWDBOSql. As this is the first (and only) result set from the execution of the RWDBOSql, the buffers are bound to the first RWDBMultiRow object accessed using the index operator on RWDBOSql.
//9 Fetches the result into the bound buffers with each call to fetch() . The call rowsFetched() returns the number of rows fetched. The call to fetch() is repeated until all rows in the result set are fetched, indicated when rowsFetched() returns 0.
//10 Uses the index operator on the bound output buffers to access the fetched data.
//11 Uses the isNull() method on the bound output buffer mgrBuff to determine if a particular entry in the buffer is NULL.
The second example assumes execution of an ad hoc query for which the schema of the result set is not known beforehand.
 
RWDBOSql openSql("SELECT * FROM emp WHERE dept = @dept", RWDBOSql::Query);
RWDBTBuffer<int> queryDeptBuff;
queryDeptBuff[0] = 3;
 
openSql << queryDeptBuff;
openSql.execute(cn);
 
const size_t ROWS_TO_FETCH = 5;
 
RWDBMultiRow mRow(openSql.schema(), ROWS_TO_FETCH); //1
openSql[0] = mRow; //2
 
long rowsFetched = 0;
while ((rowsFetched = openSql.fetch().rowsFetched()) > 0) { //3
for (size_t row = 0; row < rowsFetched; ++row) {
for (size_t col = 0; col < mRow.numberOfColumns(); ++col) { //4
RWDBValue val = mRow[row][col]; //5
if ( val.isNull() ) { //6
cout << "NULL" << "\t";
}
else {
cout << val.asString() << "\t";
}
}
cout << endl;
}
}
The steps until RWDBOSql execution are the same as in the previous example.
//1 Fetches the schema of the available result set using the schema() method on the RWDBOSql object. (You can use the RWDBSchema API to browse through the contents of the result set schema.) Here, we use the returned schema directly to create an RWDBMultiRow that creates buffers matching the datatypes of the result set columns. Each buffer will be created with ROWS_TO_FETCH entries.
//2 Assigns the created RWDBMultiRow to the RWDBOSql for use in fetching the first result set, by assigning to the 0th position in the RWDBOSql's result sets.
//3 Fetches rows into the buffers in the RWDBMultiRow with the fetch() call. The number of rows fetched is returned by the rowsFetched() call. This is repeated until all rows in the result set are fetched, indicated when rowsFetched() returns 0.
//4 Finds the number of buffers in the RWDBMultiRow using method numberOfColumns().
//5 Accesses each row’s data inside the RWDBMultiRow buffers as an RWDBRow object by calling the index operator on RWDBMultiRow and passing in the row number needed. Each value in the RWDBRow instance can then be accessed as an RWDBValue instance using the index operator on RWDBRow and passing in the column number needed.
//6 Uses the RWDBValue API to check if it is NULL. RWDBValue contains several other methods to process the value, for example, to determine the value’s type, access the value, or convert the value from one type to another.
An Open SQL Stored Procedure Example
This example illustrates how a stored procedure can be executed using an RWDBOSql object. The stored procedure used here is assumed to take one input-output parameter of type int, and to return two result sets, the first consisting of character strings and the second of two columns of types int and RWDecimalPortable. This stored procedure has a return value of type int.
This example assumes that an error handler is associated with the connection, and therefore doesn’t check for any errors after calls to the RWDBOSql object.
 
#define NUMBER_OF_ROWS 10 // Indicates the number of rows
// for the buffer
#define MAXSTRING_SIZE 255 // Maximum length of a string
// in the buffer
 
RWDBOSql openSql;
 
int inputParam = 100;
RWDBNullIndicator indA = 0;
 
RWDBTBuffer<int> paramBuffer(&inputParam, &indA, 1); //1
 
paramBuffer.paramType(RWDBColumn::inOutParameter); //2
 
char aString[NUMBER_OF_ROWS][MAXSTRING_SIZE];
memset(aString, 0, NUMBER_OF_ROWS * MAXSTRING_SIZE );
 
RWDBNullIndicator nullInd[NUMBER_OF_ROWS];
 
RWDBTBuffer<char> outCharBuffer(aString[0], nullInd,
NUMBER_OF_ROWS, MAXSTRING_SIZE); //3
 
RWDBTBuffer<int> outIntBuff(NUMBER_OF_ROWS); //4
RWDBTBuffer<RWDecimalPortable> outDecBuff(NUMBER_OF_ROWS); //5
 
RWCString sybaseSyntaxSql("mySelectStoredProc"); //6
openSql.statement(sybaseSyntaxSql, RWDBOSql::Procedure); //7
 
openSql << paramBuffer; //8
 
openSql[0] >> outCharBuffer; //9
 
openSql[1] >> outIntBuff >> outDecBuff; //10
 
openSql.execute(conn); // Execute the stored procedure
 
long count = 0;
while ( (count = openSql.fetch().rowsFetched() ) > 0 ) { //11
 
for( int row = 0; row < count; row++ ){
cout << "STRING VALUE :" << &outCharBuffer[row] << endl;
}
}
 
while ( (count = openSql.fetch().rowsFetched() ) > 0 ) { //12
 
for( int row = 0; row < count; row++ ){
cout << "INT VALUE: " << outIntBuffer[row] << endl;
cout << "DECIMAL VALUE: " << outDecBuff[row] << endl;
}
}
 
openSql.fetchReturnParams(); //13
cout << "RETURN PARAM VALUE : "<< inputParam << endl;
 
RWDBValue returnValue = openSql.returnValue(); //14
 
cout << "RETURN VALUE :" << returnValue.asInt() << endl;
 
//1 Creates a buffer for input parameters. Note the difference between this buffer creation and the buffer creation in “An Open SQL Insert Example” . In this case, an application address space is bound to the buffer.
//2 Indicates that the input buffer is intended to be an INPUT-OUTPUT parameter buffer. OUTPUT or INPUT-OUTPUT should be specified only if the parameter is expecting any return parameter values from the stored procedure execution.
//3 Creates a buffer for output values. The first result set this stored procedure returns consists of string columns less than 255 characters long. Like the input buffer example, this example uses application address space for the buffer.
//4 Creates an output buffer of type int for the second result set the stored procedure returns. Note that the buffers created here and on line //5 are not supplied the application address space. The RWDBTBuffer objects allocate and manage memory for storing the data. Each buffer has NUM_OF_ROWS entries.
//5 Creates an output buffer of type RWDecimalPortable for the second result set returned by the stored procedure.
//6 Creates a Sybase-specific SQL syntax for stored procedure invocation. In this case, the name of the stored procedure invokes the stored procedure. See //7.
//7 Associates the SQL statement with the RWDBOSql object. Note the hint provided as RWDBOSql::Procedure. Sybase in general treats all SQL statements as queries unless specified otherwise. Specifying the SQL statement as a stored procedure allows the stored procedure to be passed as an RPC command. RPC commands for stored procedure invocation result in better performance, per Sybase documentation.
//8 Associates an input buffer for the input parameter.
//9 Associates the output buffer for the first result set with the openSql object. This output buffer is bound to the first result set, indicated by the index 0.
//10 Associates the output buffers for the second result set with the openSql object. These output buffers are bound to the second result set, indicated by index 1. The buffers are bound in the order of the result set columns.
//11 Fetches rows from the first result set. Rows are fetched inside a while loop until all rows are fetched, indicated when fetch() returns 0 rows. A successful fetch places the rows in the buffer bound to the openSql object. In this case, the buffer is outCharBuffer. Note that the number of rows fetched is guaranteed to be less than or equal to the buffer's row size.
//12 Once a fetch() call returns 0 rows, the next fetch() call fetches rows from the next result set. The while loop fetches rows from the second result set into the buffers outIntBuff and outDecBuff.
//13 Makes an explicit call to fetch the return parameters. After this call, the return parameters can be expected to be available. Note that this call is made after completely processing the returned result sets.
//14 Gets the return value.