CCI Overview

CUBRID CCI (C Client Interface) driver implements an interface to enable access from C-based application to CUBRID database server through broker. It is also used as back-end infrastructure for creating tools (PHP, ODBC, etc.) which use the CAS application servers. In this environment, the CUBRID broker sends queries received from applications to a database and transfers the result to applications.

It is automatically installed upon CUBRID installation and can be found in the $CUBRID/lib directory. A header file as well as library files is required to use the driver.

  Windows UNIX/Linux
C header file include/cas_cci.h include/cas_cci.h
Static library lib/cascci.lib lib/libcascci.a
Dynamic library bin/cascci.dll lib/libcascci.so

Because CUBRID CCI driver is connected through the CUBRID broker, you can manage it the same way as other interfaces such as JDBC, PHP, ODBC, etc. In fact, CCI provides back-end infrastructure to implement PHP, ODBC, Python, and Ruby interfaces.

../_images/image54.jpg

CCI Programming

Writing CCI Applications

The applications using CCI interact with CUBRID in the process of connecting to CAS, preparing queries, executing queries, handling response, and disconnecting. In each process, CCI communicates with applications through connection handle, query handle, and response handle.

The default value of auto-commit mode can be configured by using CCI_DEFAULT_AUTOCOMMIT which is a broker parameter. If it is omitted, the default value is set to ON. To change auto-commit mode within applications, you should use the cci_set_autocommit() function. If auto-commit mode is OFF, you should explicitly commit or roll back transactions by using the cci_end_tran() function.

General process for writing applications is as follows. For using the prepared statement, additional step binding data to a variable is required; the examples 1 and 2 show the way to implement this.

Note

  • If you want to compile the CCI application on Windows, “WINDOWS” should be defined. Therefore, “-DWINDOWS” option should be defined on the compiler.
  • The database connection in thread-based programming must be used independently each other.
  • In autocommit mode, the transaction is not committed if all results are not fetched after running the SELECT statement. Therefore, although in autocommit mode, you should end the transaction by calling cci_end_tran() if some error occurs during fetching for the resultset.

Example 1

// Example to execute a simple query
// In Linux: gcc -o simple simple.c -m64 -I${CUBRID}/include -lnsl ${CUBRID}/lib/libcascci.so -lpthread

#include <stdio.h>
#include "cas_cci.h"
#define BUFSIZE  (1024)

int
main (void)
{
    int con = 0, req = 0, col_count = 0, i, ind;
    int error;
    char *data;
    T_CCI_ERROR cci_error;
    T_CCI_COL_INFO *col_info;
    T_CCI_CUBRID_STMT stmt_type;
    char *query = "select * from code";

    //getting a connection handle for a connection with a server
    con = cci_connect ("localhost", 33000, "demodb", "dba", "");
    if (con < 0)
    {
        printf ("cannot connect to database\n");
        return 1;
    }

    //preparing the SQL statement
    req = cci_prepare (con, query, 0, &cci_error);
    if (req < 0)
    {
        printf ("prepare error: %d, %s\n", cci_error.err_code,
                cci_error.err_msg);
        goto handle_error;
    }

    //getting column information when the prepared statement is the SELECT query
    col_info = cci_get_result_info (req, &stmt_type, &col_count);
    if (col_info == NULL)
    {
        printf ("get_result_info error: %d, %s\n", cci_error.err_code,
                cci_error.err_msg);
        goto handle_error;
    }

    //Executing the prepared SQL statement
    error = cci_execute (req, 0, 0, &cci_error);
    if (error < 0)
    {
        printf ("execute error: %d, %s\n", cci_error.err_code,
                cci_error.err_msg);
        goto handle_error;
    }
    while (1)
    {

        //Moving the cursor to access a specific tuple of results
        error = cci_cursor (req, 1, CCI_CURSOR_CURRENT, &cci_error);
        if (error == CCI_ER_NO_MORE_DATA)
        {
            break;
        }
        if (error < 0)
        {
            printf ("cursor error: %d, %s\n", cci_error.err_code,
                    cci_error.err_msg);
            goto handle_error;
        }

        //Fetching the query result into a client buffer
        error = cci_fetch (req, &cci_error);
        if (error < 0)
        {
            printf ("fetch error: %d, %s\n", cci_error.err_code,
                    cci_error.err_msg);
            goto handle_error;
        }
        for (i = 1; i <= col_count; i++)
        {

            //Getting data from the fetched result
            error = cci_get_data (req, i, CCI_A_TYPE_STR, &data, &ind);
            if (error < 0)
            {
                printf ("get_data error: %d, %d\n", error, i);
                goto handle_error;
            }
            printf ("%s\t|", data);
        }
        printf ("\n");
    }

    //Closing the request handle
    error = cci_close_req_handle (req);
    if (error < 0)
    {
        printf ("close_req_handle error: %d, %s\n", cci_error.err_code,
                cci_error.err_msg);
        goto handle_error;
    }

    //Disconnecting with the server
    error = cci_disconnect (con, &cci_error);
    if (error < 0)
    {
        printf ("error: %d, %s\n", cci_error.err_code, cci_error.err_msg);
        goto handle_error;
    }

    return 0;

handle_error:
    if (req > 0)
        cci_close_req_handle (req);
    if (con > 0)
    cci_disconnect (con, &cci_error);

    return 1;
}

Example 2

// Example to execute a query with a bind variable
// In Linux: gcc -o cci_bind cci_bind.c -m64 -I${CUBRID}/include -lnsl ${CUBRID}/lib/libcascci.so -lpthread

#include <stdio.h>
#include <string.h>
#include "cas_cci.h"
#define BUFSIZE  (1024)

int
main (void)
{
    int con = 0, req = 0, col_count = 0, i, ind;
    int error;
    char *data;
    T_CCI_ERROR cci_error;
    T_CCI_COL_INFO *col_info;
    T_CCI_CUBRID_STMT stmt_type;
    char *query = "select * from nation where name = ?";
    char namebuf[128];

    //getting a connection handle for a connection with a server
    con = cci_connect ("localhost", 33000, "demodb", "dba", "");
    if (con < 0)
    {
        printf ("cannot connect to database\n");
        return 1;
    }

    //preparing the SQL statement
    req = cci_prepare (con, query, 0, &cci_error);
    if (req < 0)
    {
        printf ("prepare error: %d, %s\n", cci_error.err_code,
              cci_error.err_msg);
        goto handle_error;
    }

    //Binding date into a value
    strcpy (namebuf, "Korea");
    error =
    cci_bind_param (req, 1, CCI_A_TYPE_STR, namebuf, CCI_U_TYPE_STRING,
                    CCI_BIND_PTR);
    if (error < 0)
    {
        printf ("bind_param error: %d ", error);
        goto handle_error;
    }

    //getting column information when the prepared statement is the SELECT query
    col_info = cci_get_result_info (req, &stmt_type, &col_count);
    if (col_info == NULL)
    {
        printf ("get_result_info error: %d, %s\n", cci_error.err_code,
              cci_error.err_msg);
        goto handle_error;
    }

    //Executing the prepared SQL statement
    error = cci_execute (req, 0, 0, &cci_error);
    if (error < 0)
    {
        printf ("execute error: %d, %s\n", cci_error.err_code,
              cci_error.err_msg);
        goto handle_error;
    }

    //Executing the prepared SQL statement
    error = cci_execute (req, 0, 0, &cci_error);
    if (error < 0)
    {
        printf ("execute error: %d, %s\n", cci_error.err_code,
              cci_error.err_msg);
        goto handle_error;
    }

    while (1)
    {

        //Moving the cursor to access a specific tuple of results
        error = cci_cursor (req, 1, CCI_CURSOR_CURRENT, &cci_error);
        if (error == CCI_ER_NO_MORE_DATA)
        {
            break;
        }
        if (error < 0)
        {
            printf ("cursor error: %d, %s\n", cci_error.err_code,
                  cci_error.err_msg);
            goto handle_error;
        }

        //Fetching the query result into a client buffer
        error = cci_fetch (req, &cci_error);
        if (error < 0)
        {
            printf ("fetch error: %d, %s\n", cci_error.err_code,
                  cci_error.err_msg);
            goto handle_error;
        }
        for (i = 1; i <= col_count; i++)
        {

            //Getting data from the fetched result
            error = cci_get_data (req, i, CCI_A_TYPE_STR, &data, &ind);
            if (error < 0)
            {
                printf ("get_data error: %d, %d\n", error, i);
                goto handle_error;
            }
            if (ind == -1)
            {
                printf ("NULL\t");
            }
            else
            {
                printf ("%s\t|", data);
            }
        }
            printf ("\n");
    }

    //Closing the request handle
    error = cci_close_req_handle (req);
    if (error < 0)
    {
        printf ("close_req_handle error: %d, %s\n", cci_error.err_code,
                cci_error.err_msg);
        goto handle_error;
    }

    //Disconnecting with the server
    error = cci_disconnect (con, &cci_error);
    if (error < 0)
    {
        printf ("error: %d, %s\n", cci_error.err_code, cci_error.err_msg);
        goto handle_error;
    }

    return 0;

handle_error:
    if (req > 0)
        cci_close_req_handle (req);
    if (con > 0)
        cci_disconnect (con, &cci_error);
    return 1;
}

Example 3

// Example to use connection/statement pool in CCI
// In Linux: gcc -o cci_pool cci_pool.c -m64 -I${CUBRID}/include -lnsl ${CUBRID}/lib/libcascci.so -lpthread

#include <stdio.h>
#include "cas_cci.h"

int main ()
{
    T_CCI_PROPERTIES *ps = NULL;
    T_CCI_DATASOURCE *ds = NULL;
    T_CCI_ERROR err;
    T_CCI_CONN cons;
    int rc = 1, i;

    ps = cci_property_create ();
    if (ps == NULL)
    {
        fprintf (stderr, "Could not create T_CCI_PROPERTIES.\n");
        rc = 0;
        goto cci_pool_end;
    }

    cci_property_set (ps, "user", "dba");
    cci_property_set (ps, "url", "cci:cubrid:localhost:33000:demodb:::");
    cci_property_set (ps, "pool_size", "10");
    cci_property_set (ps, "max_wait", "1200");
    cci_property_set (ps, "pool_prepared_statement", "true");
    cci_property_set (ps, "login_timeout", "300000");
    cci_property_set (ps, "query_timeout", "3000");

    ds = cci_datasource_create (ps, &err);
    if (ds == NULL)
    {
        fprintf (stderr, "Could not create T_CCI_DATASOURCE.\n");
        fprintf (stderr, "E[%d,%s]\n", err.err_code, err.err_msg);
        rc = 0;
        goto cci_pool_end;
    }

    for (i = 0; i < 3; i++)
    {
        cons = cci_datasource_borrow (ds, &err);
        if (cons < 0)
        {
            fprintf (stderr,
                    "Could not borrow a connection from the data source.\n");
            fprintf (stderr, "E[%d,%s]\n", err.err_code, err.err_msg);
            continue;
        }
        // put working code here.
        cci_work (cons);
        cci_datasource_release (ds, cons, &err);

    }

cci_pool_end:
  cci_property_destroy (ps);
  cci_datasource_destroy (ds);

  return 0;
}

// working code
int cci_work (T_CCI_CONN con)
{
    T_CCI_ERROR err;
    char sql[4096];
    int req, res, error, ind;
    int data;

    cci_set_autocommit (con, CCI_AUTOCOMMIT_TRUE);
    cci_set_lock_timeout (con, 100, &err);
    cci_set_isolation_level (con, TRAN_REP_CLASS_COMMIT_INSTANCE, &err);

    error = 0;
    snprintf (sql, 4096, "SELECT host_year FROM record WHERE athlete_code=11744");
    req = cci_prepare (con, sql, 0, &err);
    if (req < 0)
    {
        printf ("prepare error: %d, %s\n", err.err_code, err.err_msg);
        return error;
    }

    res = cci_execute (req, 0, 0, &err);
    if (res < 0)
    {
        printf ("execute error: %d, %s\n", err.err_code, err.err_msg);
        goto cci_work_end;
    }

    while (1)
    {
    error = cci_cursor (req, 1, CCI_CURSOR_CURRENT, &err);
    if (error == CCI_ER_NO_MORE_DATA)
    {
        break;
    }
    if (error < 0)
    {
        printf ("cursor error: %d, %s\n", err.err_code, err.err_msg);
        goto cci_work_end;
    }

    error = cci_fetch (req, &err);
    if (error < 0)
    {
        printf ("fetch error: %d, %s\n", err.err_code, err.err_msg);
        goto cci_work_end;
    }

    error = cci_get_data (req, 1, CCI_A_TYPE_INT, &data, &ind);
    if (error < 0)
    {
        printf ("get data error: %d\n", error);
        goto cci_work_end;
    }
    printf ("%d\n", data);
    }

    error = 1;
cci_work_end:
    cci_close_req_handle (req);
    return error;
}

Configuring Library

Once you have written applications using CCI, you should decide, according to its features, whether to execute CCI as static or dynamic link before you build it. See the table in CCI Overview to decide which library will be used.

The following is an example of Makefile, which makes a link by using the dynamic library on UNIX/Linux.

CC=gcc
CFLAGS = -g -Wall -I. -I$CUBRID/include
LDFLAGS = -L$CUBRID/lib -lcascci -lnsl
TEST_OBJS = test.o
EXES = test
all: $(EXES)
test: $(TEST_OBJS)
    $(CC) -o $@ $(TEST_OBJS) $(LDFLAGS)

The following image shows configuration to use static library on Windows.

../_images/image55.png

Using BLOB/CLOB

Storing LOB Data

You can create LOB data file and bind the data by using the functions below in CCI applications.

Example

int con = 0; /* connection handle */
int req = 0; /* request handle */
int res;
int n_executed;
int i;
T_CCI_ERROR error;
T_CCI_BLOB blob = NULL;
char data[1024] = "bulabula";

con = cci_connect ("localhost", 33000, "tdb", "PUBLIC", "");
if (con < 0) {
    goto handle_error;
}
req = cci_prepare (con, "insert into doc (doc_id, content) values (?,?)", 0, &error);
if (req< 0)
{
    goto handle_error;
}

res = cci_bind_param (req, 1 /* binding index*/, CCI_A_TYPE_STR, "doc-10", CCI_U_TYPE_STRING, CCI_BIND_PTR);

/* Creating an empty LOB data file */
res = cci_blob_new (con, &blob, &error);
res = cci_blob_write (con, blob, 0 /* start position */, 1024 /* length */, data, &error);

/* Binding BLOB data */
res = cci_bind_param (req, 2 /* binding index*/, CCI_A_TYPE_BLOB, (void *)blob, CCI_U_TYPE_BLOB, CCI_BIND_PTR);

n_executed = cci_execute (req, 0, 0, &error);
if (n_executed < 0)
{
    goto handle_error;
}

/* Commit */
if (cci_end_tran(con, CCI_TRAN_COMMIT, &error) < 0)
{
    goto handle_error;
}

/* Memory free */
cci_blob_free(blob);
return 0;

handle_error:
if (blob != NULL)
{
    cci_blob_free(blob);
}
if (req > 0)
{
    cci_close_req_handle (req);
}
if (con > 0)
{
    cci_disconnect(con, &error);
}
return -1;

Retrieving LOB Data

You can retrieve LOB data by using the following functions in CCI applications. Note that if you enter data in the LOB type column, the actual LOB data is stored in the file located in external storage and Locator value is stored in the LOB type column. Thus, to retrieve the LOB data stored in the file, you should call the cci_blob_read() function but the cci_get_data() function.

  • Retrieving meta data (Locator) in the the LOB type column (related function: cci_get_data())
  • Retrieving the LOB data (related function: cci_blob_read())
  • Freeing memory for the LOB struct: (related function: cci_blob_free())

Example

int con = 0; /* connection handle */
int req = 0; /* request handle */
int ind; /* NULL indicator, 0 if not NULL, -1 if NULL*/
int res;
int i;
T_CCI_ERROR error;
T_CCI_BLOB blob;
char buffer[1024];

con = cci_connect ("localhost", 33000, "image_db", "PUBLIC", "");
if (con < 0)
{
    goto handle_error;
}
req = cci_prepare (con, "select content from doc_t", 0 /*flag*/, &error);
if (req< 0)
{
    goto handle_error;
}

res = cci_execute (req, 0/*flag*/, 0/*max_col_size*/, &error);

while (1) {
    res = cci_cursor (req, 1/* offset */, CCI_CURSOR_CURRENT/* cursor position */, &error);
    if (res == CCI_ER_NO_MORE_DATA)
    {
        break;
    }
    res = cci_fetch (req, &error);

    /* Fetching CLOB Locator */
    res = cci_get_data (req, 1 /* colume index */, CCI_A_TYPE_BLOB,
    (void *)&blob /* BLOB handle */, &ind /* NULL indicator */);
    /* Fetching CLOB data */
    res = cci_blob_read (con, blob, 0 /* start position */, 1024 /* length */, buffer, &error);
    printf ("content = %s\n", buffer);
}

/* Memory free */
cci_blob_free(blob);
res=cci_close_req_handle(req);
res = cci_disconnect (con, &error);
return 0;

handle_error:
if (req > 0)
{
    cci_close_req_handle (req);
}
if (con > 0)
{
    cci_disconnect(con, &error);
}
return -1;

CCI Error Codes and Error Messages

CCI API functions return a negative number as CCI or CAS (broker application server) error codes when an error occurs. The CCI error codes occur in CCI API functions and CAS error codes occur in CAS.

  • All error codes are negative.
  • All error codes and error messages of functions which have “T_CCI_ERROR err_buf” as a parameter can be found on err_buf.err_code and err_buf.err_msg.
  • All error messages of functions which have no “T_CCI_ERROR err_buf” as a parameter can output by using cci_get_err_msg().
  • If the value of error code is between -20002 and -20999, it is caused by CCI API functions.
  • If the value of error code is between -10000 and -10999, it is caused by CAS and transferred by CCI API functions. For CAS errors, see CAS Error.
  • If the value of error code is CCI_ER_DBMS (-20001), it is caused by database server. You can check server error codes in err_buf.err_code of the database error buffer (err_buf). For database server errors, see Database Server Errors.

Warning

If an error occurs in server, the value of CCI_ER_DBMS, which is error code returned by a function may be different from the value of the err_buf.err_code. Except server errors, every error code stored in err_buf is identical to that returned by a function.

Note

CCI and CAS error codes have different values between the earlier version of CUBRID 9.0 and the version of CUBRID 9.0 or later. Therefore, the users who developed the applications by using the error code names must recompile them and the users who developed them by directly assigning error code numbers must recompile them after changing the number values.

The database error buffer (err_buf) is a struct variable of T_CCI_ERROR defined in the cas_cci.h header file. For how to use it, see the example below.

CCI error codes which starting with CCI_ER are defined in enum called T_CCI_ERROR_CODE under the $CUBRID/include/cas_cci.h file. Therefore, to use this error code name in program code, you should include a header file in the upper side of code by entering #include “cas_cci.h”.

The following example shows how to display error messages. In the example, the error code value (req) returned by cci_prepare() is CCI_ER_DBMS. -493 (server error code) is stored in cci_error.err_code and the error message, ‘Syntax: Unknown class “notable”. select * from notable’ is stored in cci_error.err_msg of the database error buffer.

// gcc -o err err.c -m64 -I${CUBRID}/include -lnsl ${CUBRID}/lib/libcascci.so -lpthread
#include <stdio.h>
#include "cas_cci.h"

#define BUFSIZE  (1024)

int
main (void)
{
    int con = 0, req = 0, col_count = 0, i, ind;
    int error;
    char *data;
    T_CCI_ERROR err_buf;
    char *query = "select * from notable";

    //getting a connection handle for a connection with a server
    con = cci_connect ("localhost", 33000, "demodb", "dba", "");
    if (con < 0)
    {
        printf ("cannot connect to database\n");
        return 1;
    }

    //preparing the SQL statement
    req = cci_prepare (con, query, 0, &err_buf);
    if (req < 0)
    {
        if (req == CCI_ER_DBMS)
        {
            printf ("error from server: %d, %s\n", err_buf.err_code, err_buf.err_msg);
        }
        else
        {
            printf ("error from cci or cas: %d, %s\n", err_buf.err_code, err_buf.err_msg);
        }
        goto handle_error;
    }
    // ...
}

The following list shows CCI error codes. For CAS errors, see CAS Error.

Error Code (Error Number) Error Message Note
CCI_ER_DBMS (-20001) CUBRID DBMS Error Error codes returned by functions when an error occurs in server. The causes of the error can be checked with err_code and err_msg stored in the T_CCI_ERROR struct.
CCI_ER_CON_HANDLE (-20002) Invalid connection handle  
CCI_ER_NO_MORE_MEMORY (-20003) Memory allocation error Insufficient memory
CCI_ER_COMMUNICATION (-20004) Cannot communicate with server  
CCI_ER_NO_MORE_DATA (-20005) Invalid cursor position  
CCI_ER_TRAN_TYPE (-20006) Unknown transaction type  
CCI_ER_STRING_PARAM (-20007) Invalid string argument An error occurred when sql_stmt is NULL in cci_prepare(), and cci_prepare_and_execute()
CCI_ER_TYPE_CONVERSION (-20008) Type conversion error Cannot convert the given value into an actual data type.
CCI_ER_BIND_INDEX (-20009) Parameter index is out of range Index that binds data is not valid.
CCI_ER_ATYPE (-20010) Invalid T_CCI_A_TYPE value  
CCI_ER_NOT_BIND (-20011)   Not available
CCI_ER_PARAM_NAME (-20012) Invalid T_CCI_DB_PARAM value  
CCI_ER_COLUMN_INDEX (-20013) Column index is out of range  
CCI_ER_SCHEMA_TYPE (-20014)   Not available
CCI_ER_FILE (-20015) Cannot open file Fails to open/read/write a file.
CCI_ER_CONNECT (-20016) Cannot connect to CUBRID CAS Cannot connect to CUBRID CAS
CCI_ER_ALLOC_CON_HANDLE (-20017) Cannot allocate connection handle %  
CCI_ER_REQ_HANDLE (-20018) Cannot allocate request handle %  
CCI_ER_INVALID_CURSOR_POS (-20019) Invalid cursor position  
CCI_ER_OBJECT (-20020) Invalid oid string  
CCI_ER_CAS (-20021)   Not available
CCI_ER_HOSTNAME (-20022) Unknown host name  
CCI_ER_OID_CMD (-20023) Invalid T_CCI_OID_CMD value  
CCI_ER_BIND_ARRAY_SIZE (-20024) Array binding size is not specified  
CCI_ER_ISOLATION_LEVEL (-20025) Unknown transaction isolation level  
CCI_ER_SET_INDEX (-20026) Invalid set index Invalid index is specified when a set element in the T_CCI_SET struct is retrieved.
CCI_ER_DELETED_TUPLE (-20027) Current row was deleted %  
CCI_ER_SAVEPOINT_CMD (-20028) Invalid T_CCI_SAVEPOINT_CMD value Invalid T_CCI_SAVEPOINT_CMD value is used as an argument of the cci_savepoint() function.
CCI_ER_THREAD_RUNNING(-20029) Invalid T_CCI_SAVEPOINT_CMD value Invalid T_CCI_SAVEPOINT_CMD value is used as an argument of the cci_savepoint() function.
CCI_ER_INVALID_URL (-20030) Invalid url string  
CCI_ER_INVALID_LOB_READ_POS (-20031) Invalid lob read position  
CCI_ER_INVALID_LOB_HANDLE (-20032) Invalid lob handle  
CCI_ER_NO_PROPERTY (-20033) Could not find a property  
CCI_ER_PROPERTY_TYPE (-20034) Invalid property type  
CCI_ER_INVALID_DATASOURCE (-20035) Invalid CCI datasource  
CCI_ER_DATASOURCE_TIMEOUT (-20036) All connections are used  
CCI_ER_DATASOURCE_TIMEDWAIT (-20037) pthread_cond_timedwait error  
CCI_ER_LOGIN_TIMEOUT (-20038) Connection timed out  
CCI_ER_QUERY_TIMEOUT (-20039) Request timed out  
CCI_ER_RESULT_SET_CLOSED (-20040)    
CCI_ER_INVALID_HOLDABILITY (-20041) Invalid holdability mode. The only accepted values are 0 or 1  
CCI_ER_NOT_UPDATABLE (-20042) Request handle is not updatable  
CCI_ER_INVALID_ARGS (-20043) Invalid argument  
CCI_ER_USED_CONNECTION (-20044) This connection is used already.  

C Type Definition

The following shows the structs used in CCI API functions.

Name Type Member Description
T_CCI_ERROR struct char err_msg[1024] Representation of database error info
int err_code
T_CCI_BIT struct int size Representation of bit type
char *buf
T_CCI_DATE struct short yr Representation of datetime, timestamp, date, and time type
short mon
short day
short hh
short mm
short ss
short ms
T_CCI_DATE_TZ struct short yr Representation of date/time types with timezone
short mon
short day
short hh
short mm
short ss
short ms
char tz[64]
T_CCI_SET void*   Representation of set type
T_CCI_COL_INFO struct T_CCI_U_EXT_TYPE type Representation of column information for the SELECT statement
char is_non_null
short scale
int precision
char *col_name
char *real_attr
char *class_name
T_CCI_QUERY_RESULT struct int result_count Results of batch execution
int stmt_type
char *err_msg
char oid[32]
T_CCI_PARAM_INFO struct T_CCI_PARAM_MODE mode Representation of input parameter info
T_CCI_U_EXT_TYPE type
short scale
int precision
T_CCI_U_EXT_TYPE unsigned char   Database type info
T_CCI_U_TYPE enum CCI_U_TYPE_UNKNOWN Database type info
CCI_U_TYPE_NULL
CCI_U_TYPE_CHAR
CCI_U_TYPE_STRING
CCI_U_TYPE_BIT
CCI_U_TYPE_VARBIT
CCI_U_TYPE_NUMERIC
CCI_U_TYPE_INT
CCI_U_TYPE_SHORT
CCI_U_TYPE_FLOAT
CCI_U_TYPE_DOUBLE
CCI_U_TYPE_DATE
CCI_U_TYPE_TIME
CCI_U_TYPE_TIMESTAMP
CCI_U_TYPE_SET
CCI_U_TYPE_MULTISET
CCI_U_TYPE_SEQUENCE
CCI_U_TYPE_OBJECT
CCI_U_TYPE_BIGINT
CCI_U_TYPE_DATETIME
CCI_U_TYPE_BLOB
CCI_U_TYPE_CLOB
CCI_U_TYPE_ENUM
CCI_U_TYPE_UINT
CCI_U_TYPE_USHORT
CCI_U_TYPE_UBIGINT
CCI_U_TYPE_TIMESTAMPTZ
CCI_U_TYPE_TIMESTAMPLTZ
CCI_U_TYPE_DATETIMETZ
CCI_U_TYPE_DATETIMELTZ
T_CCI_A_TYPE enum CCI_A_TYPE_STR Representation of type info used in API
CCI_A_TYPE_INT
CCI_A_TYPE_FLOAT
CCI_A_TYPE_DOUBLE
CCI_A_TYPE_BIT
CCI_A_TYPE_DATE
CCI_A_TYPE_SET
CCI_A_TYPE_BIGINT
CCI_A_TYPE_BLOB
CCI_A_TYPE_CLOB
CCI_A_TYPE_CLOB
CCI_A_TYPE_REQ_HANDLE
CCI_A_TYPE_UINT
CCI_A_TYPE_UBIGINT
CCI_A_TYPE_DATE_TZ
CCI_A_TYPE_UINT
T_CCI_DB_PARAM enum CCI_PARAM_ISOLATION_LEVEL System parameter names
CCI_PARAM_LOCK_TIMEOUT
CCI_PARAM_MAX_STRING_LENGTH
CCI_PARAM_AUTO_COMMIT
T_CCI_SCH_TYPE enum CCI_SCH_CLASS  
CCI_SCH_VCLASS
CCI_SCH_QUERY_SPEC
CCI_SCH_ATTRIBUTE
CCI_SCH_CLASS_ATTRIBUTE
CCI_SCH_METHOD
CCI_SCH_CLASS_METHOD
CCI_SCH_METHOD_FILE
CCI_SCH_SUPERCLASS
CCI_SCH_SUBCLASS
CCI_SCH_CONSTRAIT
CCI_SCH_TRIGGER
CCI_SCH_CLASS_PRIVILEGE
CCI_SCH_ATTR_PRIVILEGE
CCI_SCH_DIRECT_SUPER_CLASS
CCI_SCH_PRIMARY_KEY
CCI_SCH_IMPORTED_KEYS
CCI_SCH_EXPORTED_KEYS
CCI_SCH_CROSS_REFERENCE
T_CCI_CUBRID_STMT enum CUBRID_STMT_ALTER_CLASS  
CUBRID_STMT_ALTER_SERIAL
CUBRID_STMT_COMMIT_WORK
CUBRID_STMT_REGISTER_DATABASE
CUBRID_STMT_CREATE_CLASS
CUBRID_STMT_CREATE_INDEX
CUBRID_STMT_CREATE_TRIGGER
CUBRID_STMT_CREATE_SERIAL
CUBRID_STMT_DROP_DATABASE
CUBRID_STMT_DROP_CLASS
CUBRID_STMT_DROP_INDEX
CUBRID_STMT_DROP_LABEL
CUBRID_STMT_DROP_TRIGGER
CUBRID_STMT_DROP_SERIAL
CUBRID_STMT_EVALUATE
CUBRID_STMT_RENAME_CLASS
CUBRID_STMT_ROLLBACK_WORK
CUBRID_STMT_GRANT
CUBRID_STMT_REVOKE
CUBRID_STMT_STATISTICS
CUBRID_STMT_INSERT
CUBRID_STMT_SELECT
CUBRID_STMT_UPDATE
CUBRID_STMT_DELETE
CUBRID_STMT_CALL
CUBRID_STMT_GET_ISO_LVL
CUBRID_STMT_GET_TIMEOUT
CUBRID_STMT_GET_OPT_LVL
CUBRID_STMT_SET_OPT_LVL
CUBRID_STMT_SCOPE
CUBRID_STMT_GET_TRIGGER
CUBRID_STMT_SET_TRIGGER
CUBRID_STMT_SAVEPOINT
CUBRID_STMT_PREPARE
CUBRID_STMT_ATTACH
CUBRID_STMT_USE
CUBRID_STMT_REMOVE_TRIGGER
CUBRID_STMT_RENAME_TRIGGER
CUBRID_STMT_ON_LDB
CUBRID_STMT_GET_LDB
CUBRID_STMT_SET_LDB
CUBRID_STMT_GET_STATS
CUBRID_STMT_CREATE_USER
CUBRID_STMT_DROP_USER
CUBRID_STMT_ALTER_USER
CUBRID_STMT_SET_SYS_PARAMS
CUBRID_STMT_ALTER_INDEX
CUBRID_STMT_CREATE_STORED_PROCEDURE
CUBRID_STMT_DROP_STORED_PROCEDURE
CUBRID_STMT_PREPARE_STATEMENT
CUBRID_STMT_EXECUTE_PREPARE
CUBRID_STMT_DEALLOCATE_PREPARE
CUBRID_STMT_TRUNCATE
CUBRID_STMT_DO
CUBRID_STMT_SELECT_UPDATE
CUBRID_STMT_SET_SESSION_VARIABLES
CUBRID_STMT_DROP_SESSION_VARIABLES
CUBRID_STMT_MERGE
CUBRID_STMT_SET_NAMES
CUBRID_STMT_ALTER_STORED_PROCEDURE
CUBRID_STMT_KILL
T_CCI_CURSOR_POS enum CCI_CURSOR_FIRST  
CCI_CURSOR_CURRENT
CCI_CURSOR_LAST
T_CCI_TRAN_ISOLATION enum TRAN_READ_COMMITTED  
TRAN_REPEATABLE_READ
TRAN_SERIALIZABLE
T_CCI_PARAM_MODE enum CCI_PARAM_MODE_UNKNOWN  
CCI_PARAM_MODE_IN
CCI_PARAM_MODE_OUT
CCI_PARAM_MODE_INOUT

Note

If a string longer than defined max length is inserted (INSERT) or updated (UPDATE), the string will be truncated.

CCI Sample Program

The sample program shows how to write a CCI application by using the demodb database which is included with the CUBRID installation package. You can practice the ways to connect to CAS, prepare queries, execute queries, handle response, disconnect from CAS, etc. by following sample program below. In the sample program, the dynamic link on Linux environment is used.

The code below shows information about olympic table schema in the demodb database which is used for sample program.

csql> ;sc olympic

=== <Help: Schema of a Class> ===


 <Class Name>

     olympic

 <Attributes>

     host_year            INTEGER NOT NULL
     host_nation          CHARACTER VARYING(40) NOT NULL
     host_city            CHARACTER VARYING(20) NOT NULL
     opening_date         DATE NOT NULL
     closing_date         DATE NOT NULL
     mascot               CHARACTER VARYING(20)
     slogan               CHARACTER VARYING(40)
     introduction         CHARACTER VARYING(1500)

 <Constraints>

     PRIMARY KEY pk_olympic_host_year ON olympic (host_year)

Preparing

Make sure that the demodb database and the broker are running before you execute the sample program. You can start the demodb database and the broker by executing the cubrid utility. The code below shows how to run a database server and broker by executing the cubrid utility.

[tester@testdb ~]$ cubrid server start demodb
@ cubrid master start
++ cubrid master start: success
@ cubrid server start: demodb

This may take a long time depending on the amount of recovery works to do.

CUBRID 9.2

++ cubrid server start: success
[tester@testdb ~]$ cubrid broker start
@ cubrid broker start
++ cubrid broker start: success

Building

With the program source and the Makefile prepared, executing make will create an executable file named test. If you use a static library, there is no need to deploy additional files and the execution will be faster. However, it increases the program size and memory usage. If you use a dynamic library, there will be some performance overhead but the program size and memory usage can be optimized.

The code below a command line that makes a test program build by using a dynamic library instead of using make on Linux.

cc -o test test.c -I$CUBRID/include -L$CUBRID/lib -lnsl -lcascci

Sample Code

#include <stdio.h>
#include <cas_cci.h>
char *cci_client_name = "test";
int main (int argc, char *argv[])
{
    int con = 0, req = 0, col_count = 0, res, ind, i;
    T_CCI_ERROR error;
    T_CCI_COL_INFO *res_col_info;
    T_CCI_CUBRID_STMT stmt_type;
    char *buffer, db_ver[16];
    printf("Program started!\n");
    if ((con=cci_connect("localhost", 30000, "demodb", "PUBLIC", ""))<0) {
        printf( "%s(%d): cci_connect fail\n", __FILE__, __LINE__);
        return -1;
    }

    if ((res=cci_get_db_version(con, db_ver, sizeof(db_ver)))<0) {
        printf( "%s(%d): cci_get_db_version fail\n", __FILE__, __LINE__);
        goto handle_error;
    }
    printf("DB Version is %s\n",db_ver);
    if ((req=cci_prepare(con, "select * from event", 0,&error))<0) {
        if (req < 0) {
            printf( "%s(%d): cci_prepare fail(%d)\n", __FILE__, __LINE__,error.err_code);
        }
        goto handle_error;
    }
    printf("Prepare ok!(%d)\n",req);
    res_col_info = cci_get_result_info(req, &stmt_type, &col_count);
    if (!res_col_info) {
        printf( "%s(%d): cci_get_result_info fail\n", __FILE__, __LINE__);
        goto handle_error;
    }

    printf("Result column information\n"
           "========================================\n");
    for (i=1; i<=col_count; i++) {
        printf("name:%s  type:%d(precision:%d scale:%d)\n",
            CCI_GET_RESULT_INFO_NAME(res_col_info, i),
            CCI_GET_RESULT_INFO_TYPE(res_col_info, i),
            CCI_GET_RESULT_INFO_PRECISION(res_col_info, i),
            CCI_GET_RESULT_INFO_SCALE(res_col_info, i));
    }
    printf("========================================\n");
    if ((res=cci_execute(req, 0, 0, &error))<0) {
        if (req < 0) {
            printf( "%s(%d): cci_execute fail(%d)\n", __FILE__, __LINE__,error.err_code);
        }
        goto handle_error;
    }

    while (1) {
        res = cci_cursor(req, 1, CCI_CURSOR_CURRENT, &error);
        if (res == CCI_ER_NO_MORE_DATA) {
            printf("Query END!\n");
            break;
        }
        if (res<0) {
            if (req < 0) {
                printf( "%s(%d): cci_cursor fail(%d)\n", __FILE__, __LINE__,error.err_code);
            }
            goto handle_error;
        }

        if ((res=cci_fetch(req, &error))<0) {
            if (res < 0) {
                printf( "%s(%d): cci_fetch fail(%d)\n", __FILE__, __LINE__,error.err_code);
            }
            goto handle_error;
        }

        for (i=1; i<=col_count; i++) {
            if ((res=cci_get_data(req, i, CCI_A_TYPE_STR, &buffer, &ind))<0) {
                printf( "%s(%d): cci_get_data fail\n", __FILE__, __LINE__);
                goto handle_error;
            }
            printf("%s \t|", buffer);
        }
        printf("\n");
    }
    if ((res=cci_close_req_handle(req))<0) {
        printf( "%s(%d): cci_close_req_handle fail", __FILE__, __LINE__);
       goto handle_error;
    }
    if ((res=cci_disconnect(con, &error))<0) {
        if (res < 0) {
            printf( "%s(%d): cci_disconnect fail(%d)", __FILE__, __LINE__,error.err_code);
        }
        goto handle_error;
    }
    printf("Program ended!\n");
    return 0;

    handle_error:
    if (req > 0)
        cci_close_req_handle(req);
    if (con > 0)
        cci_disconnect(con, &error);
    printf("Program failed!\n");
    return -1;
}