|
Open Client Client-Library/C Reference Manual
|
Examples
Example 1
The example below shows ct_setparam being
used in code that declares, opens, and reopens a cursor that takes
parameters.
Example: ct_setparam for
reopening a cursor
/*
** Data structures to describe a parameter and a cursor.
*/
typedef struct _langparam
{ CS_CHAR *name;
CS_INT type;
CS_INT len;
CS_INT maxlen;
CS_VOID *data;
CS_SMALLINT indicator;
} LANGPARAM;
typedef struct _cur_control
{ CS_CHAR *name;
CS_CHAR *query;
LANGPARAM *params;
CS_INT numparams;
} CUR_CONTROL;
/*
** Static data for a parameterized cursor body.
*/
CS_STATIC CS_MONEY PriceVal;
CS_STATIC CS_INT SalesVal;
CS_STATIC LANGPARAM Params [] =
{ { "@price_val", CS_MONEY_TYPE, CS_SIZEOF(CS_MONEY), CS_SIZEOF(CS_MONEY),
(CS_VOID *)&PriceVal, 0
},
{ "@sales_val", CS_INT_TYPE, CS_SIZEOF(CS_INT), CS_SIZEOF(CS_INT),
(CS_VOID *)&SalesVal, 0
},
};
#define NUMPARAMS (CS_SIZEOF(Params) / CS_SIZEOF(LANGPARAM))
#define QUERY \
"select title_id, title, price, total_sales from titles \
where price > @price_val and total_sales > @sales_val \
for read only"
CS_STATIC CUR_CONTROL Cursor_Control =
{ "curly", QUERY, Params, NUMPARAMS };/*
** OpenCursor() -- Declare and open a new cursor or reopen
** an existing cursor (which must have been originally
** declared and opened using this function).
**
** If the open is successful, this function processes the cursor
** results up to the CS_CURSOR_RESULT result type value. In
** other words, the command handle is ready for
** ct_bind/ct_fetch/etc.
**
** Parameters
** cmd -- CS_COMMAND handle for the new cursor.
** cur_control -- address of a CUR_CONTROL structure that contains
** the cursor body statement plus parameter formats and value
** areas.
**
** If a first-time open is successful, OpenCursor() can be used to
** reopen the cursor with new parameter values.
**
** For later opens, the cursor must be closed.
**
** Returns
** CS_SUCCEED or CS_FAIL
*/
CS_RETCODE
OpenCursor(cmd, cur_control)
CS_COMMAND *cmd;
CUR_CONTROL *cur_control;
{ CS_RETCODE ret;
CS_INT i;
CS_DATAFMT dfmt;
LANGPARAM *params;
CS_BOOL have_restorable_cursor;
/*
** Check whether a cursor-open command can be restored with this
** command handle.
*/
ret = ct_cmd_props(cmd, CS_GET, CS_HAVE_CUROPEN,
&have_restorable_cursor, CS_UNUSED,
(CS_INT *)NULL);
if (ret != CS_SUCCEED)
{ ex_error("OpenCursor: ct_cmd_props() failed!"); return CS_FAIL;
}
/*
** If CS_HAVE_CUROPEN is CS_FALSE, then this is a first-time open. So,
** we initiate a new declare command and bind to the parameter source
** variables in the CUR_CONTROL structure.
*/
if (have_restorable_cursor != CS_TRUE)
{ /*
** Initiate the declare command.
*/
ret = ct_cursor(cmd, CS_CURSOR_DECLARE,
cur_control->name, CS_NULLTERM,
cur_control->query, CS_NULLTERM,
CS_UNUSED);
if (ret != CS_SUCCEED)
{ ex_error("OpenCursor: Initiate-declare failed"); return CS_FAIL;
}
/*
** Specify formats for the host language parameters in the cursor
** declare command.
*/
params = cur_control->params;
(CS_VOID *)memset(&dfmt, sizeof(dfmt), 0);
dfmt.status = CS_INPUTVALUE;
for (i = 0; i < cur_control->numparams; i++)
{ dfmt.datatype = params[i].type;
dfmt.maxlength = params[i].maxlen;
strcpy(dfmt.name, params[i].name);
dfmt.namelen = strlen(dfmt.name);
ret = ct_setparam(cmd, &dfmt,
(CS_VOID *)NULL, (CS_INT *)NULL,
(CS_SMALLINT *)NULL);
if (ret != CS_SUCCEED)
{ ex_error("OpenCursor: ct_setparam() failed"); return CS_FAIL;
}
}
}
/*
** Initiate or restore the cursor-open command.
**
** The first time we open the cursor, this call initiates an
** open-cursor command which gets batched with the declare command.
** Since there is no cursor to restore, ct_cursor ignores the
** CS_RESTORE_OPEN option.
**
** The second (and later) times we open the cursor, this call
** restores the cursor-open command so that we can send it again.
** The declare-cursor command (originally batched with the open
** command) is not restored.
*/
ret = ct_cursor(cmd, CS_CURSOR_OPEN,
(CS_CHAR *)NULL, CS_UNUSED,
(CS_CHAR *)NULL, CS_UNUSED,
CS_RESTORE_OPEN);
if (ret != CS_SUCCEED)
{ ex_error("OpenCursor: Initiate-open failed."); return CS_FAIL;
}
/*
** For the first-time open, supply the address of variables that have
** values for the cursor parameters. These variables will be read by
** ct_send.
**
** The second (and later) times we open the cursor, we don't have to
** call ct_setparam here -- the parameter bindings were restored by
** ct_cursor(OPEN, RESTORE_OPEN).
**
** In either case, we assume that our caller has already set the
** desired values, lengths, and indicators.
*/
for (i = 0;
((have_restorable_cursor != CS_TRUE) &&
(i < cur_control->numparams));
i++)
{ dfmt.datatype = params[i].type;
dfmt.maxlength = params[i].maxlen;
strcpy(dfmt.name, params[i].name);
dfmt.namelen = strlen(dfmt.name);
ret = ct_setparam(cmd, &dfmt,
params[i].data, ¶ms[i].len,
¶ms[i].indicator);
if (ret != CS_SUCCEED)
{ ex_error("OpenCursor: ct_setparam() failed"); return CS_FAIL;
}
}
/*
** Send the command batch.
*/
ret = ct_send(cmd);
if (ret != CS_SUCCEED)
{ ex_error("OpenCursor: ct_send() failed."); return CS_FAIL;
}
/*
** GetToCursorRows() calls ct_results() until cursor rows are
** fetchable on the command structure. GetToCursorRows() fails if
** the declare or open command fails on the server.
*/
ret = GetToCursorRows(cmd);
if (ret != CS_SUCCEED)
{ ex_error("OpenCursor: Cursor could not be opened."); return CS_FAIL;
}
return CS_SUCCEED;
} /* OpenCursor() */
/*
** GetToCursorRows() -- Flush results from a cursor-open command
** batch until ct_results returns a CS_CURSOR_RESULT result type.
**
** Parameters
** cmd -- The command handle to read results from.
**
** Returns
** CS_SUCCEED -- Cursor rows are ready to be fetched.
** CS_FAIL -- Failure. Could be due to any of the following:
** - No cursor results in the results stream.
** - Other kinds of fetchable results in the results stream.
** - ct_results failure.
*/
CS_STATIC CS_RETCODE
GetToCursorRows(cmd)
CS_COMMAND *cmd;
{ CS_RETCODE results_ret;
CS_RETCODE ret;
CS_INT result_type = CS_END_RESULTS;
CS_BOOL failing = CS_FALSE;
CS_INT intval;
CS_CHAR scratch[512];
while (((results_ret = ct_results(cmd, &result_type)) == CS_SUCCEED)
&& (result_type != CS_CURSOR_RESULT))
{ switch ((int)result_type)
{ case CS_CMD_SUCCEED:
case CS_CMD_DONE:
break;
case CS_CMD_FAIL:
/*
** Declare or open failed on the server.
*/
ret = ct_res_info(cmd, CS_CMD_NUMBER, (CS_VOID *)&intval,
CS_UNUSED, (CS_INT *)NULL);
if (ret == CS_SUCCEED)
{ sprintf(scratch, "Command %ld failed", (long)intval);
ex_error(scratch);
}
failing = CS_TRUE;
break;
default:
/*
** Nothing else is expected. Just return fail and let the caller
** decide how to clean up.
*/
ex_error(
"Unexpected result types received for cursor declare/open.");
return CS_FAIL;
}
}
/*
** We are leaving the cursor results pending on the connection.
*/
if (results_ret == CS_CANCELED)
{ /*
** Could happen if the connection has a timeout and the error
** handler did ct_cancel(CS_CANCEL_ATTN);
*/
ex_error("Cursor declare/open was canceled."); failing = CS_TRUE;
}
else if (results_ret != CS_SUCCEED)
{ ex_error("Cursor declare/open: ct_results failed."); failing = CS_TRUE;
}
return (failing == CS_TRUE) ? CS_FAIL : CS_SUCCEED;
} /* GetToCursorRows() */