Sybase Technical Library - Product Manuals Home
[Search Forms] [Previous Section with Hits] [Next Section with Hits] [Clear Search] Expand Search

Preface [Table of Contents] Chapter 2: Topics

Open Client Client-Library/C Reference Manual

[-] Chapter 1: Introducing Client-Library

Chapter 1

Introducing Client-Library

Client/Server Architecture

Client/server architecture divides the work of computing between "clients" and "servers."

Clients make requests of servers and process the results of those requests. For example, a client application might request data from a database server. Another client application might send a request to an environmental control server to lower the temperature in a room.

Servers respond to requests by returning data or other information to clients, or by taking some action. For example, a database server returns tabular data and information about that data to clients, and an electronic mail server directs incoming mail toward its final destination.

raster Figure 1-1: Client/Server architecture

Client/server architecture has several advantages over traditional program architectures:

Types of Clients

A client is any application that makes requests of a server. Clients include:

Types of Servers

The SYBASE product line includes servers and tools for building servers:

An Open Server application can be any type of server. For example, an Open Server application can perform specialized calculations, provide access to real time data, or interface with services such as electronic mail. An Open Server application is created individually, using the building blocks provided by Open Server Server-Library.

SQL Server and Open Server applications are similar in some ways:

But they also differ:

The following diagram illustrates some of the different capabilities of SQL Server and Open Server applications:

raster Figure 1-2: SQL Server and Open Server applications

The Open Client and Open Server Products

Sybase provides two families of products to enable customers to write client and server application programs. They are:

SYBASE Open Client

SYBASE Open Client provides customer applications, third-party products, and other SYBASE products with the interfaces needed to communicate with SQL Server and Open Server.

Open Client can be thought of as having two components, programming interfaces and network services.

The programming interfaces component of Open Client is made up of libraries designed for use in writing client applications: Client-Library, DB-Library, and CS-Library. (Both Open Client and Open Server include CS-Library, which contains utility routines that are useful to both client and server applications.)

Open Client network services include Net-Libraryä, which provides support for specific network protocols, such as TCP/IP or DECnet.

SYBASE Open Server

SYBASE Open Server provides the tools and interfaces needed to create custom servers.

Like Open Client, Open Server has a programming interfaces component and a network services component.

The programming interfaces component of Open Server contains Server-Library and CS-Library. (Both Open Client and Open Server include CS-Library, which contains utility routines that are useful to both client and server applications.)

Open Server network services are transparent.

Application Calls to Libraries

The following diagram illustrates the Open Client and Open Server library calls that different types of applications might make. For example, a client application might include calls to Client-Library and CS-Library, while an application that acts as both client and server (for example, a gateway application) might include calls to Client-Library, CS-Library, and Server-Library:

raster Figure 1-3: Application calls to libraries

The Open Client Libraries

The libraries that make up Open Client programming interfaces are:

What Is in Client-Library?

Client-Library includes routines that send commands to a server and routines that process the results of those commands. Other routines set application properties, handle error conditions, and provide a variety of information about an application's interaction with a server.

Client-Library also contains a header file, ctpublic.h, that defines structures, types, and values used by Client-Library routines.

Client-Library is a Generic Interface

Client-Library is a generic interface. Through Open Server and gateway applications, Client-Library applications can run against foreign applications and servers as well as SQL Server.

Because it is generic, Client-Library does not enforce or reflect any particular server's restrictions. For example, Client-Library allows text and image stored procedure parameters, but SQL Server does not.

When writing a Client-Library application, keep the application's ultimate target server in mind. If you are unsure about what is legal on a server and what is not, consult your server documentation.

An application can call ct_capability to find out what capabilities a particular client/server connection supports.

Comparing the Library Approach to Embedded SQL

Either an Open Client library application or an Embedded SQL application can be used to send SQL commands to SQL Server.

An Embedded SQL application includes SQL commands in-line. The host language precompiler processes the commands into calls to Open Client libraries. All SYBASE 10.0 precompilers use a run-time library composed solely of documented Client-Library and CS-Library calls.

In a sense, then, the precompiler transforms an Embedded SQL application into an Open Client library application.

An Open Client library application sends SQL commands through library routines, and does not require a precompiler.

Generally, an Embedded SQL application is easier to write and debug, but a library application can take fuller advantage of the flexibility and power of Open Client routines.

Using Client-Library

An application programmer writes a Client-Library program, using calls to Client-Library and CS-Library routines to set up structures, connect to servers, send commands, process results, and clean up. A Client-Library program is compiled and run in the same way as any other C language program.

Basic Control Structures

In order to send commands to a server, a Client-Library application must allocate three types of structures:

An application allocates these structures by calling the CS-Library and Client-Library routines cs_ctx_alloc, ct_con_alloc, and ct_cmd_alloc.

The general relationship between the three basic control structures is illustrated by the following diagram :

raster Figure 1-4: Relationship of control structures

Through these structures, an application sets up its environment, connects to servers, sends commands, and processes results.

For more information about these control structures, see "Structures" in Chapter 2, "Topics," or the Client-Library Programmer's Guide.

Steps in a Simple Program

On most platforms, a simple Client-Library program involves the following steps:

The example program in the following section demonstrates these steps.

A Simple Example Program

The following example demonstrates the basic framework of a Client-Library application. The program follows the steps outlined in the previous section, sending a language command to a SQL Server and processing the results of the command. In this case, the language command is a Transact-SQL select command.

For brevity's sake, this program does not include code for the message callback routines that handle Client-Library and server messages. However, message callback routines are included with the on-line example programs.

/*
** Language Query Example Program.
*/

#include <stdio.h>
#include <ctpublic.h>

/*
** Define a global context structure to use
*/
CS_CONTEXT *context;

#define ERROR_EXIT (-1)
#define MAXCOLUMNS 2
#define MAXSTRING 40

extern int print_data();

/* Client message and server message callback routines: */
CS_RETCODE clientmsg_callback();
CS_RETCODE servermsg_callback();
void error();

/*
** Main entry point for the program.
*/
main(argc, argv)
int argc;

char **argv;
{
CS_CONNECTION *connection; /* Connection structure. */
CS_COMMAND *cmd; /* Command structure. */

/* Data format structures for column descriptions: */
CS_DATAFMT columns[MAXCOLUMNS];

CS_INT datalength[MAXCOLUMNS];
CS_SMALLINT indicator[MAXCOLUMNS];
CS_INT count;
CS_RETCODE ret, res_type;
CS_CHAR name[MAXSTRING];
CS_CHAR city[MAXSTRING];

/*
** Get a context structure to use.
*/
cs_ctx_alloc(CS_VERSION_100, &context)

/*
** Initialize Open Client.
*/
ct_init(context, CS_VERSION_100);

/*
** Install message callback routines.
*/
ct_callback(context, NULL, CS_SET, CS_CLIENTMSG_CB,
clientmsg_callback);

ct_callback(context, NULL, CS_SET, CS_SERVERMSG_CB,
servermsg_callback);

/*
** Connect to the server:
** Allocate a connection structure.
** Set user name and password.
** Create the connection.
*/
ct_con_alloc(context, &connection);
ct_con_props(connection, CS_SET, CS_USERNAME, "username",
CS_NULLTERM, NULL);
ct_con_props(connection, CS_SET, CS_PASSWORD, "password",
CS_NULLTERM, NULL);

/*
** This call actually creates the connection:
*/
ct_connect(connection, "servername", CS_NULLTERM);

/*
** Allocate a command structure.
*/
ct_cmd_alloc(connection, &cmd);

/*
** Initiate a language command.
*/
ct_command(cmd, CS_LANG_CMD,
"use pubs2 \
select au_lname, city from pubs2..authors \
where state = 'CA'",
CS_NULLTERM, CS_UNUSED);

/*
** Send the command.
*/
ct_send(cmd);

/*
** Process the results of the command.
*/
while((ret = ct_results(cmd, &res_type))== CS_SUCCEED)
{
switch (res_type)
{
case CS_ROW_RESULT:
/*
** We're expecting exactly two columns.
** For each column, fill in the relevant
** fields in a data format structure, and
** bind the column.
*/
columns[0].datatype = CS_CHAR_TYPE;
columns[0].format = CS_FMT_NULLTERM;
columns[0].maxlength = MAXSTRING;
columns[0].count = 1;
columns[0].locale = NULL;
ct_bind(cmd, 1, &columns[0], name, &datalength[0],
&indicator[0]);

columns[1].datatype = CS_CHAR_TYPE;
columns[1].format = CS_FMT_NULLTERM;
columns[1].maxlength = MAXSTRING;
columns[1].count = 1;
columns[1].locale = NULL;
ct_bind(cmd, 2, &columns[1], city, &datalength[1],
&indicator[1]);

/*
** Now fetch and print the rows.
*/
while(((ret = ct_fetch(cmd, CS_UNUSED, CS_UNUSED,
CS_UNUSED, &count))
== CS_SUCCEED) || (ret == CS_ROW_FAIL))
{
/*
** Check if we hit a recoverable error.
*/
if( ret == CS_ROW_FAIL )
{
fprintf(stderr,
"Error on row %d in this fetch batch.",
count+1);
}

/*
** We have a row, let's print it.
*/
fprintf(stdout, "%s: %s\n", name, city);
}

/*
** We're finished processing rows, so check
** ct_fetch's final return value.
*/
if( ret == CS_END_DATA )
{
fprintf(stdout,
"All done processing rows.");
}
else /* Failure occurred. */
{
error("ct_fetch failed");
}

/*
** All done with this result set.
*/
break;

case CS_CMD_SUCCEED:
/*
** Executed a command that never returns rows.
*/
fprintf(stderr, "No rows returned.\n");
break;


case CS_CMD_FAIL:
/*
** The server encountered an error while
** processing our command.
*/
break;

case CS_CMD_DONE;
/*
** The logical command has been completely
** processed.
*/
break;

default:
/*
** We got something unexpected.
*/
error("ct_result returned unexpected result
type");
break;
}
}

/*
** We've finished processing results. Let's check
** the return value of ct_results() to see if
** everything went ok.
*/
switch(ret)
{
case CS_END_RESULTS:
/*
** Everything went fine.
*/
break;

case CS_FAIL:
/*
** Something terrible happened.
*/
error("ct_results() returned FAIL.");
break;

default:
/*
** We got an unexpected return value.
*/
error("ct_result returned unexpected return
code");
break;
}

** All done.
*/
ct_cmd_drop(cmd);
ct_close(connection, CS_UNUSED);
ct_con_drop(connection);
ct_exit(context, CS_UNUSED);
cs_ctx_drop(context);
return 0;
}

/*
** Error occurred, cleanup and exit.
*/
void error(msg)
char *msg;
{
fprintf(stderr, "FATAL ERROR: %s\n", msg);
exit(ERROR_EXIT);
}

Notes on the Example Program

The header file ctpublic.h is required in all source files that contain calls to Client-Library/C. It defines symbolic constants used by Client-Library routines and contains typedefs for Client-Library datatypes.

Setting Up the Client-Library Programming Environment

The CS-Library routine cs_ctx_alloc allocates a context structure. A context structure is used to store configuration parameters that describe a particular "context," or operating environment, for a set of server connections. On most platforms, an application can have multiple contexts, although a typical application will need just one.

Application properties that can be defined at the context level include the name and location of the interfaces file, the login timeout value, and the maximum number of connections allowed within the context.

ct_init initializes Client-Library. An application calls ct_init after calling cs_ctx_alloc and before calling any other Client-Library routine.

Installing Message Callback Routines

ct_callback installs a Client-Library callback routine. Callbacks are custom routines which are called automatically by Client-Library when a triggering event of the appropriate type occurs. For example, a client message callback is called automatically whenever OC-Library generates an error or informational message.

There are several types of callbacks, but the example program installs only two: a client message callback, to handle Client-Library error and informational messages, and a server message callback, to handle server error and informational messages. Code for the callbacks is not supplied with this example.

Note: Callback routines are not supported for all programming language/ platform combinations.If callbacks are not supported for a programming language/platform version of Client-Library, the Open Client/Server Supplement for that language and platform will indicate the lack of support.

Connecting to a Server

ct_con_alloc allocates a connection structure. A connection structure contains information about a particular client/server connection.

ct_con_props sets and retrieves the values of a connection's properties. Connection properties include user name and password, which are used in logging into a server; application name, which appears in SQL Server's sysprocess table, and packet size, which determines the size of network packets that an application will send and receive. For a complete list of connection properties, see the Properties topics page.

The example program sets only the user name and password properties.

ct_connect opens a connection to a server, logging into the server with the connection information specified via ct_con_props.

Sending a Command to the Server

ct_cmd_alloc allocates a command structure. A command structure is used to send commands to a server and to process the results of those commands.

ct_command initiates the process of sending a non-cursor command. In this case, the example program initiates a language command.

ct_send sends a command to the server.

Processing the Results of the Command

Almost all Client-Library programs will process results by using a loop controlled by ct_results. Inside the loop, a switch takes place on the current type of result. Different types of results require different types of processing.

For row results, typically the number of columns in the result set is determined and then used to control a loop in which result items are bound to program variables. An application can call ct_res_info to get the number of result columns, but in the example this is not necessary, because exactly two columns were selected. After the result items are bound, ct_fetch is called to fetch data rows until end-of-data.

The results processing model used in the example looks like this:

while ct_results returns CS_SUCCEED
switch on result_type
case row results
for each column:
ct_bind
end for
while ct_fetch is returning rows
process each row
end while
check ct_fetch's final return code
end case row results
case other result type....
case other result type....
....
end switch
end while
check ct_results' final return code

ct_results sets up results for processing. ct_results' return parameter result_type indicates the type of result data that is available for processing. Because the example program expects only a single result set of type CS_ROW_RESULT, most result types are not included as cases in the switch on result_type.

Note that the example program calls ct_results in a loop that continues as long as ct_results returns CS_SUCCEED, indicating that result sets are available for processing. Although this type of program structure is not strictly necessary in the case of a simple language command, it is highly recommended. In more complex programs, it is not possible to predict the number and type of result sets than an application will receive in response to a command.

ct_bind binds a result item to a program variable. Binding creates an association between a result item and a program data space.

ct_fetch fetches result data. In the example, since binding has been specified and the count field in the CS_DATAFMT structure for each column is set to 1, each ct_fetch call copies one row of data into program data space. As each row is fetched, the example program prints it.

After the ct_fetch loop terminates, the example program checks its final return code to find out whether we dropped out because of end-of-data, or because of failure.

Finishing Up

ct_cmd_drop de-allocates a command structure.

ct_close closes a server connection.

ct_con_drop de-allocates a connection structure.

ct_exit terminates Client-Library.

The CS-Library routine cs_ctx_drop de-allocates a context structure.

More Advanced Programs

Although some Client-Library applications will be as simple as the example program in this chapter, most will be more complex. Client-Library is a rich programming interface that supports a variety of advanced features.

Some of these features are:

For more information on these and other advanced features, see Chapter 2, "Topics" .


Preface [Table of Contents] Chapter 2: Topics