Send a chunk of text or image data to the server.
CS_RETCODE ct_send_data(cmd, buffer, buflen) CS_COMMAND *cmd; CS_VOID *buffer; CS_INT buflen;
A pointer to the CS_COMMAND structure managing a client/server operation.
A pointer to the value to write to the server.
The length, in bytes, of *buffer.
CS_NULLTERM is not a legal value for buflen.
ct_send_data returns the following values:
Return value |
Meaning |
---|---|
CS_SUCCEED |
The routine completed successfully. |
CS_FAIL |
The routine failed. |
CS_CANCELED |
The send data operation was canceled. |
CS_PENDING |
Asynchronous network I/O is in effect. See “Asynchronous programming”. |
CS_BUSY |
An asynchronous operation is already pending for this connection. See “Asynchronous programming”. |
The following fragment illustrates the call sequence to build and send a send-data command:
/*
** 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;
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;
}
This code excerpt is from the getsend.c sample program.
The following fragment illustrates the call sequence to send 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; }
This code excerpt is from the uctext.c sample program.
An application can use ct_send_data to write a text or image value to a database column providing the user has update privileges granted for the underlying table, which may be in a different database and not in the view. This writing operation is actually an update; that is, the column must have a value when ct_send_data is called to write a new value.
This is because ct_send_data uses text timestamp information when writing to the column, and a column does not have a valid text timestamp until it contains a value. The value contained in the text or image column can be NULL, but the NULL must be entered explicitly with the SQL update statement.
For information on the steps involved in using ct_send_data to update a text or image column, see “Updating a text or image column”. For information about sending partial updates with ct_send_data, see “Sending partial updates with ct_send_data”.
To perform a send-data operation, an application must have a current I/O descriptor, or CS_IODESC structure, describing the column value that will be updated:
The textptr field of the CS_IODESC identifies the target column.
The timestamp field of the CS_IODESC is the text timestamp of the column value. If timestamp does not match the current database text timestamp for the value, the update operation fails.
The total_txtlen field of the CS_IODESC indicates the total length, in bytes, of the column’s new value. An application must call ct_send_data in a loop to write exactly this number of bytes before calling ct_send to indicate the end of the text or image update operation.
The log_on_update of the CS_IODESC tells the server whether or not to log the update operation.
The locale field of the CS_IODESC points to a CS_LOCALE structure that contains localization information for the new value, if any.
A typical application will change only the values of the locale, total_txtlen, and log_on_update fields before using an I/O descriptor in an update operation, but an application that is updating the same column value multiple times will need to change the value of the timestamp field as well.
A successful text or image update generates a parameter result set that contains the new text timestamp for the text or image value. If an application plans to update the text or image value a second time, it must save this new text timestamp and copy it into the CS_IODESC for the value before calling ct_data_info to define the CS_IODESC for the update operation.
A text or image update operation is equivalent to a language command containing a Transact-SQL update statement.
The command space identified by cmd must be idle before a text or image update operation is initiated. A command space is idle if there are no active commands, pending results, or open cursors in the space.
To update a text or image column, a client application typically calls the ct_command routine to initiate a send-data command. The client then calls the ct_data_info command to retrieve the CS_IODESC and determine the appropriate SQL command to generate (update or writetext) in a subsequent call to the ct_send_data routine.
To simplify this process and potentially improve performance, a client can suppress the generation of the SQL command (update or writetext) and send data directly to the server bulk handler. To do this, the client must initiate the send-data command by calling the ct_command routine with the type parameter set to CS_SEND_DATA_NOCMD. The client application can then use send-data commands to send only text or image data to the server bulk handler. When a bulk event occurs at the server, a 4-byte field is sent indicating the total number of bytes to be sent, followed by the text or image data. The bulk handler reads the total number of bytes expected using srv_text_info and the data using srv_get_data.
The server must define a stored procedure, sp_mda, to indicate whether or not it supports the ct_send_data routine sending only text or image data without a SQL command. The server sp_mda procedure is called only if the client application sets certain properties—for example, ct_con_props(CS_SENDDATA_NOCMD)—before the ct_connect routine is called. If any of these properties (such as CS_PARTIAL_TEXT or the CS_SENDDATA_NOCMD connection property) is set, the server sp_mda procedure is called during execution of ct_connect. If sp_mda indicates that the server does not support the ct_send_data routine sending only text or image data without a SQL command, any calls to the ct_command routine with the type parameter set to CS_SEND_DATA_NOCMD fail.
If the server can receive text or image data without a SQL command, sp_mda returns:
Parameter |
Value |
---|---|
mdinfo |
“SENDDATA_NOCMD” |
querytype |
2 |
query |
senddata no cmd |
Adaptive Server cannot receive image or text data without a SQL command.