Client-Library usage

This section discusses the Open Client APIs that have been introduced or modified to support partial updates. For a sample program, see $SYBASE/$SYBASE_OCS/sample/ctlib/uctext.c.


CS_PARTIAL_TEXT

CS_PARTIAL_TEXT is a new property that indicates whether or not the client needs to perform a partial update. You can set this property in the connection or context level using ct_con_props() or ct_config(), respectively. The possible values of CS_PARTIAL_TEXT are CS_TRUE and CS_FALSE.

The CS_PARTIAL_TEXT property must be set before a connection to the server is established. If the server does not support partial updates, CS_PARTIAL_TEXT is set to CS_FALSE, which is the default value.


CS_IODESC

The CS_IODESC structure has been modified to support the partial update of text and image columns. The new iotype value CS_IOPARTIAL specifies that a partial update must be performed on the text or image column while the new field delete_length indicates the number of bytes that must be overwritten or deleted from the column. The reserved field offset, on the other hand, indicates the first byte in the column that is affected by the partial update

To perform a partial update, use ct_data_info() to set iotype, delete_length, and offset. The values of delete_length and of the data passed to the server through ct_send_data() determine the behavior of the partial update:

delete_length

Text data

Server action

0

Provided

Insert the text data at offset.

!= 0

Provided

Starting from offset, overwrite delete_length bytes of data with text data.

!= 0

Not provided

Starting at offset, delete delete_length bytes of data.

NULL

Provided / Not provided

Delete data starting from offset to the end of the text or image column.

New CS_IODESC structure

The new CS_IODESC structure is:

typedef struct _cs_iodesc
{
        CS_INT iotype;
        CS_INT datatype;
        CS_LOCALE *locale;
        CS_INT usertype;
        CS_INT total_txtlen;
        CS_INT offset;
        CS_BOOL log_on_update;
        CS_CHAR name[CS_OBJ_NAME];
        CS_INT namelen;
        CS_BYTE timestamp[CS_TS_SIZE];
        CS_INT timestamplen;
        CS_BYTE textptr[CS_TP_SIZE];
        CS_INT textptrlen;
        CS_INT delete_length;
} CS_IODESC;

Backward compatibility

Applications that have been compiled with the old CS_IODESC structure definition can still link to shared libraries that use the new CS_IODESC structure. Because the old application has not set the iotype to CS_IOPARTIAL, the new shared libraries will not access delete_length, thus maintaining backward compatibility.


ct_send_data()

ct_send_data() has been extended to support partial updates. Currently, to send data, ct_send_data() constructs a Transact-SQL writetext statement and the data is sent in chunks using multiple ct_send_data() calls. You can use this same method to send partially updated data. However, ct_send_data() will construct an udpatetext statement instead of a writetext. The updatetext syntax is:

updatetext table_name.column_name text_pointer 
   {NULL | offset} {NULL | delete_length} [with_log]

NoteThe updatetext statement is created only if iotype is set to CS_IOPARTIAL.

This example shows ct_send_data() sending partial update data:

/*
** UpdateTextData()
*/
CS_STATIC CS_RETCODE
UpdateTextData(connection, textdata, newdata)
CS_CONNECTION connection;
TEXT_DATA textdata;
char *newdata;
{
   CS_RETCODE retcode;
   CS_INT res_type;
   CS_COMMAND  *cmd;
   CS_INT      i;
   CS_TEXT     *txtptr;
   CS_INT       txtlen;
   /*
   ** Allocate a command handle to send the text with
   */
   ...CODE DELETED.....
   /*
   ** Inform Client-Library the next data sent will 
   ** be used for a text or image update.
   */
   if ((retcode = ct_command(cmd, CS_SEND_DATA_CMD,
   NULL, CS_UNUSED, CS_COLUMN_DATA)) != CS_SUCCEED)
   {
      ex_error("UpdateTextData: ct_command() \ 
         failed");
      return retcode;
   }
   /*
   ** Fill in the description information for the 
   ** update and send it to Client-Library.
   */
   txtptr = (CS_TEXT *)newdata;
   txtlen = strlen(newdata);
   textdata->iodesc.total_txtlen = txtlen;
   textdata->iodesc.log_on_update = CS_TRUE;
   /*
   **  Insert newdata at offset 20.
   */
   textdata->iodesc.iotype = CS_IOPARTIAL;
   textdata->iodesc.offset = 20;
   textdata->iodesc.delete_length = 0;
   retcode = ct_data_info(cmd, CS_SET, CS_UNUSED,
   &textdata->iodesc);
   if (retcode != CS_SUCCEED)
   {
      ex_error("UpdateTextData: ct_data_info() \ 
         failed");
      return retcode;
   }
   /*
   ** Send the text one byte at a time. This is not
   ** the best thing to do for performance reasons,
   ** but does demonstrate that ct_send_data()
   ** can handle arbitrary amounts of data.
   */
   for (i = 0; i < txtlen; i++, txtptr++)
   {
      retcode = ct_send_data(cmd, txtptr,(CS_INT)1);
      if (retcode != CS_SUCCEED)
      {
         ex_error("UpdateTextData: ct_send_data() \ 
            failed");
         return retcode;
      }
   }
   /*
   ** ct_send_data() writes to internal network 
   ** buffers. To insure that all the data is 
   ** flushed to the server, a ct_send() is done.
   */
   if ((retcode = ct_send(cmd)) != CS_SUCCEED)
   {
      ex_error("UpdateTextData: ct_send() failed");
      return retcode;
   }
   /* Process the results of the command */
   while ((retcode = ct_results(cmd, &res_type)) ==
      CS_SUCCEED)
   {
      switch ((int)res_type)
      {
         case CS_PARAM_RESULT:
            /*
            ** Retrieve a description of the
            ** parameter data. Only timestamp data is
            ** expected in this example.
            */
            retcode = ProcessTimestamp(cmd, textdata);
            if (retcode != CS_SUCCEED)
            {
               ex_error("UpdateTextData: \ 
                 ProcessTimestamp() failed");
               /*
               ** Something failed, so cancel all
               ** results.
               */
               ct_cancel(NULL, cmd, CS_CANCEL_ALL);
               return retcode;
            }
            break;
         case CS_CMD_SUCCEED:
         case CS_CMD_DONE:
            /*
            ** This means that the command succeeded
            ** or is finished.
            */
            break;
         case CS_CMD_FAIL:
            /*
            ** The server encountered an error while
            ** processing our command.
            */
            ex_error("UpdateTextData: ct_results() \ 
               returned CS_CMD_FAIL");
            break;
         default:
            /*
            ** We got something unexpected.
            */
            ex_error("UpdateTextData: ct_results() \ 
               returned unexpected result type”);
            /* Cancel all results */
            ct_cancel(NULL, cmd, CS_CANCEL_ALL);
            break;
      }
   }
   /*
   ** We're done processing results. Let's check the
   ** return value of ct_results() to see if 
   ** everything went ok.
   */
   ...CODE DELETED.....
   return retcode;
}

For information about ct_send_data(), see the Open Client Client-Library/C Reference Manual.


Handling of unitext data

If the client application uses 2-byte Unicode datatypes, the application must make sure that it sends an even number of bytes to avoid a character split. You can use the buflen parameter of ct_send_data() and the total_txtlen field of CS_IODESC to specify the length, in bytes, of the Unicode data. For Unitext, the offset and delete_length values must be specified as a character count while total_txtlen must be specified in bytes. For other datatypes, the offset, delete_length, and total_txtlen must be in bytes.