Win32-SqlServer
view release on metacpan or search on metacpan
senddata.cpp view on Meta::CPAN
case DBTYPE_SQLVARIANT :
* (SSVARIANT *) buffer_ptr = value.sql_variant;
break;
case DBTYPE_TABLE :
// First check that the table has been defined.
if (value.table->rowset_ptr != NULL) {
* (IRowsetChange **) buffer_ptr = value.table->rowset_ptr;
}
else {
olle_croak(olle_ptr,
"Cannot execute batch: %d column(s) left to define for table-valued parameter",
value.table->cols_undefined);
}
break;
default :
olle_croak(olle_ptr, "Internal error: unhandled type %d", typeind);
break;
}
}
// Retrieves a key value from the QH hash. The value must be defined, and
// a string value must not be the empty string.
static SV * get_QN_hash(HV * hv,
const char * key)
{
SV ** svp;
SV * sv = NULL;
SV * ret = NULL;
svp = hv_fetch(hv, key, (int) strlen(key), 0);
if (svp != NULL) {
sv = *svp;
}
if (my_sv_is_defined(sv)) {
if (SvPOK(sv) && SvCUR(sv) >= 1) {
ret = sv;
}
else if (! SvPOK(sv)) {
ret = sv;
}
}
return ret;
}
//-------------------------------------------------------------------
// set_rowset_properties, this is a subroutine to executebatch.
//-------------------------------------------------------------------
static void set_rowset_properties (SV * olle_ptr,
internaldata * mydata)
{
IV optCommandTimeout = OptCommandTimeout(olle_ptr);
HV * optQN = OptQueryNotification(olle_ptr);
ICommandProperties * property_ptr;
DBPROP property[3];
int no_of_props = 0;
DBPROPSET property_set[2];
int no_of_propsets = 0;
HRESULT ret;
if (optCommandTimeout > 0) {
// There are a lot of properties in DBPROPSET_ROWSET, but we only care
// about this single one.
property[0].dwPropertyID = DBPROP_COMMANDTIMEOUT;
property[0].dwOptions = DBPROPOPTIONS_REQUIRED;
property[0].colid = DB_NULLID;
VariantInit(&property[0].vValue);
property[0].vValue.vt = VT_I4;
property[0].vValue.lVal = (LONG) optCommandTimeout;
property_set[0].guidPropertySet = DBPROPSET_ROWSET;
property_set[0].cProperties = 1;
property_set[0].rgProperties = property;
no_of_propsets++;
}
// Check for query notification - but not if we run the nested
// query to get the codepage.
if (optQN && ! mydata->isnestedquery) {
SV * sv_service;
SV * sv_message;
SV * sv_timeout;
no_of_props = 0;
// First, see if there is a service. Only if there is a service we
// will submit any query notification at all.
sv_service = get_QN_hash(optQN, "Service");
if (sv_service != NULL) {
if (mydata->provider >= provider_sqlncli) {
property[no_of_props].dwPropertyID = SSPROP_QP_NOTIFICATION_OPTIONS;
property[no_of_props].dwOptions = DBPROPOPTIONS_REQUIRED;
property[no_of_props].colid = DB_NULLID;
VariantInit(&property[no_of_props].vValue);
property[no_of_props].vValue.vt = VT_BSTR;
property[no_of_props].vValue.bstrVal = SV_to_BSTR(sv_service);
no_of_props++;
}
else if (PL_dowarn) {
olledb_message(olle_ptr, -1, 1, 10,
L"QueryNotification option ignored when provider is SQLOLEDB.");
sv_service = NULL;
}
}
else if (PL_dowarn && SvTRUE(hv_scalar(optQN))) {
// If there were other elements in the hash, the user has messed up.
olledb_message(olle_ptr, -1, 1, 10,
L"The QueryNotification property had elements, but no Service element. No notification was submitted.");
}
// We must add a message, so if the user did not provide one, we will.
sv_message = get_QN_hash(optQN, "Message");
if (sv_service != NULL) {
property[no_of_props].dwPropertyID = SSPROP_QP_NOTIFICATION_MSGTEXT;
property[no_of_props].dwOptions = DBPROPOPTIONS_REQUIRED;
property[no_of_props].colid = DB_NULLID;
VariantInit(&property[no_of_props].vValue);
property[no_of_props].vValue.vt = VT_BSTR;
property[no_of_props].vValue.bstrVal =
(sv_message != NULL ? SV_to_BSTR(sv_message) :
SysAllocString(L"Query notification set by Win32::SqlServer"));
no_of_props++;
}
// The timeout on the other hand is optional.
sv_timeout = get_QN_hash(optQN, "Timeout");
if (sv_service != NULL && sv_timeout != NULL) {
property[no_of_props].dwPropertyID = SSPROP_QP_NOTIFICATION_TIMEOUT;
property[no_of_props].dwOptions = DBPROPOPTIONS_REQUIRED;
property[no_of_props].colid = DB_NULLID;
VariantInit(&property[no_of_props].vValue);
property[no_of_props].vValue.vt = VT_UI4;
property[no_of_props].vValue.ulVal = (ULONG) SvIV(sv_timeout);
no_of_props++;
}
// Wipe out the hash.
hv_clear(optQN);
if (no_of_props > 0) {
property_set[no_of_propsets].guidPropertySet = DBPROPSET_SQLSERVERROWSET;
property_set[no_of_propsets].cProperties = no_of_props;
property_set[no_of_propsets].rgProperties = property;
no_of_propsets++;
}
}
if (no_of_propsets > 0) {
// Get a property pointer.
ret = mydata->cmdtext_ptr->QueryInterface(IID_ICommandProperties,
(void **) &property_ptr);
check_for_errors(olle_ptr, "cmdtext_ptr->QueryInterface to create Property object", ret);
ret = property_ptr->SetProperties(no_of_propsets, property_set);
check_for_errors(NULL, "property_ptr->SetProperties for rowset props", ret);
property_ptr->Release();
}
// We must free up memory allocated to the BSTRs in the QN propset.
if (optQN) {
for (int i = 0; i < no_of_props; i++) {
VariantClear(&property[no_of_props].vValue);
}
}
}
//-------------------------------------------------------------------
// $X->executebatch.
//-------------------------------------------------------------------
int executebatch(SV *olle_ptr,
SV *sv_rows_affected)
{
internaldata * mydata = get_internaldata(olle_ptr);
BOOL has_params = (mydata->no_of_params > 0);
HRESULT ret;
paramdata * current_param;
DBPARAMBINDINFO * cur_param_info;
DBBINDING * cur_binding;
DB_UPARAMS * param_ordinals;
DBORDINAL param_ix = 0;
DBBYTEOFFSET value_offset;
DBBYTEOFFSET len_offset;
DBBYTEOFFSET status_offset;
BOOL final_retval = TRUE;
ISessionProperties * sess_property_ptr;
DBPROP property[1];
DBPROPSET property_set[1];
DBROWCOUNT rows_affected;
DBPARAMS param_parameter; // Parameter to cmdtext->Execute.
SSPARAMPROPS * ss_param_props = NULL; // SQL-server specific parameter properies.
DB_UPARAMS ss_param_props_cnt = 0;
// There must be no sesssion_ptr, this indicates that a previous command
// has not been completely processed.
if (mydata->cmdtext_ptr != NULL) {
olle_croak(olle_ptr, "Cannot submit a new batch, when previous batch has not been processed");
}
// And check that we have a pending command to execute.
if (mydata->pending_cmd == NULL) {
olle_croak(olle_ptr, "There is no pending command to execute. Call initbatch first");
}
// Make sure that we have datasrc and session pointers set up.
if (! setup_session(olle_ptr)) {
return FALSE;
}
// If any input parameter failed, to convert, we are not letting you by.
if (! mydata->all_params_OK) {
olledb_message(olle_ptr, -1, 1, 16,
L"One or more parameters were not convertible. Cannot execute query.");
free_batch_data(mydata);
return FALSE;
}
// Commands with parameters require a whole lot more of works than
// those with out.
senddata.cpp view on Meta::CPAN
memset(mydata->param_buffer, 0, mydata->size_param_buffer);
// Iterate over the list to copy the binding and parambindinfo structs,
// set ordinals and and fill in values to the paramdata buffer.
current_param = mydata->paramfirst;
cur_param_info = mydata->param_info;
cur_binding = mydata->param_bindings;
while (current_param != NULL) {
// Parameter ordinal.
param_ordinals[param_ix] = param_ix + 1;
// Copy structures
cur_binding[param_ix] = current_param->binding;
cur_param_info[param_ix] = current_param->param_info;
// Get offsets to use.
value_offset = current_param->binding.obValue;
len_offset = current_param->binding.obLength;
status_offset = current_param->binding.obStatus;
// And then fill in the parameter buffer, which is more work.
if (current_param->isinput) {
// Write status.
DBSTATUS * status =
(DBSTATUS *) (&mydata->param_buffer[status_offset]);
if (! current_param->isnull) {
* status = DBSTATUS_S_OK;
}
else if (current_param->datatype == DBTYPE_TABLE) {
* status = DBSTATUS_S_DEFAULT;
}
else {
* status = DBSTATUS_S_ISNULL;
}
if (! current_param->isnull) {
// If not NULL, we need to write input value.
DBLENGTH * len_ptr = NULL;
if (current_param->binding.dwPart & DBPART_LENGTH) {
len_ptr = (DBLENGTH *) (&mydata->param_buffer[len_offset]);
* len_ptr = current_param->value_len;
}
write_to_databuffer(olle_ptr, mydata->param_buffer,
value_offset, current_param->datatype,
current_param->value);
}
/* Good debug,
wprintf(L"Param_name = %s, status = %d, value = %d.\n",
current_param->param_info.pwszName,
current_param->binding.obStatus,
current_param->binding.obValue);
*/
}
// Add parameter properties. These are not available with SQLOLEDB.
if (current_param->param_props_cnt > 0 &&
mydata->provider >= provider_sqlncli) {
DBPROPSET * propset;
New(902, propset, 2 * current_param->param_props_cnt, DBPROPSET);
propset->rgProperties = current_param->param_props;
propset->cProperties = current_param->param_props_cnt;
propset->guidPropertySet = DBPROPSET_SQLSERVERPARAMETER;
ss_param_props[ss_param_props_cnt].rgPropertySets = propset;
ss_param_props[ss_param_props_cnt].cPropertySets = 1;
ss_param_props[ss_param_props_cnt].iOrdinal =
param_ordinals[param_ix];
// If it's a table parameter with default values, there's
// one more property.
if (current_param->datatype == DBTYPE_TABLE &&
! current_param->isnull &&
current_param->value.table->no_of_usedefault > 0) {
propset[1].rgProperties =
&(current_param->value.table->defcolprop);
propset[1].cProperties = 1;
propset[1].guidPropertySet = DBPROPSET_SQLSERVERPARAMETER;
ss_param_props[ss_param_props_cnt].cPropertySets++;
}
ss_param_props_cnt++;
}
// Move to next.
current_param = current_param->next;
param_ix++;
}
// Must allocate space for bindstatus.
New(902, mydata->param_bind_status, mydata->no_of_params, DBBINDSTATUS);
} // if has_params
// We need a property object for the session
ret = mydata->session_ptr->QueryInterface(IID_ISessionProperties,
(void **) &sess_property_ptr);
check_for_errors(olle_ptr, "session_ptr->QueryInterface to create Property object", ret);
// We always want the SQL Server-native representation of variant data.
property[0].dwPropertyID = SSPROP_ALLOWNATIVEVARIANT;
property[0].dwOptions = DBPROPOPTIONS_REQUIRED;
property[0].colid = DB_NULLID;
VariantInit(&property[0].vValue);
property[0].vValue.vt = VT_BOOL;
property[0].vValue.boolVal = VARIANT_TRUE;
property_set[0].guidPropertySet = DBPROPSET_SQLSERVERSESSION;
property_set[0].cProperties = 1;
property_set[0].rgProperties = property;
ret = sess_property_ptr->SetProperties(1, property_set);
check_for_errors(NULL, "property_ptr->SetProperties for ssvariant prop", ret);
sess_property_ptr->Release();
// Command-text interface.
ret = mydata->session_ptr->CreateCommand(NULL, IID_ICommandText,
(IUnknown **) &(mydata->cmdtext_ptr));
check_for_errors(olle_ptr, "session_ptr->CreateCommand for command-text object", ret);
// Set rowset properties from Win32::SqlServer options.
set_rowset_properties(olle_ptr, mydata);
// Set the command text.
ret = mydata->cmdtext_ptr->SetCommandText(DBGUID_SQL, mydata->pending_cmd);
check_for_errors(olle_ptr, "cmdtext_ptr->SetCommandText", ret);
// Again, extra stuff for commands with parameters
if (has_params) {
// Command-with-parameter interface
ret = mydata->cmdtext_ptr->QueryInterface(IID_ICommandWithParameters,
(void **) &(mydata->paramcmd_ptr));
check_for_errors(olle_ptr, "cmdtext_ptr->QueryInterface for ICommandWithParameters", ret);
// Set parameter info. Here we permit execution to proceed in case of
// errors, as it could be user errors like using the xml datatype with
// SQLEOLEDB.
ret = mydata->paramcmd_ptr->SetParameterInfo(mydata->no_of_params,
( run in 0.555 second using v1.01-cache-2.11-cpan-71847e10f99 )