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 )