Win32-SqlServer
view release on metacpan or search on metacpan
* User: Sommar Date: 08-04-30 Time: 22:46
* Updated in $/Perl/OlleDB
* Use get_sv and not perl_get_sv (deprecated). Pass GV_ADDMULTI to get_sv
* to avoid "Used only once" warning. Don't define macro XS_VERSION in the
* file, as it comes with the Makefile.
*
* ***************** Version 2 *****************
* User: Sommar Date: 08-01-06 Time: 23:33
* Updated in $/Perl/OlleDB
* Replaced all unsafe CRT functions with their safe replacements in VC8.
* olledb_message now takes a va_list as argument, so we pass it
* parameterised strings and don't have to litter the rest of the code
* with that.
*
* ***************** Version 1 *****************
* User: Sommar Date: 07-12-24 Time: 21:40
* Created in $/Perl/OlleDB
---------------------------------------------------------------------*/
#define _WIN32_DCOM // Needed for CoInitializeEx
#include "CommonInclude.h"
#include <cguid.h>
#include <msdaguid.h>
#include "convenience.h"
#include "datatypemap.h"
#include "init.h"
#undef FILEDEBUG
#ifdef FILEDEBUG
FILE *dbgfile = NULL;
#endif
// Global variables for class ids for the possible providers.
CLSID clsid_sqloledb = CLSID_NULL;
CLSID clsid_sqlncli = CLSID_NULL;
CLSID clsid_sqlncli10 = CLSID_NULL;
CLSID clsid_sqlncli11 = CLSID_NULL;
CLSID clsid_msoledbsql = CLSID_NULL;
CLSID clsid_msoledbsql19 = CLSID_NULL;
// This global array holds definition of all initialisation properties
// for OLE DB.
init_property gbl_init_props[MAX_INIT_PROPERTIES];
// Number of properties per provider:
int no_of_ssprops_sqloledb = -1;
int no_of_ssprops_sqlncli = -1;
int no_of_ssprops_sqlncli10 = -1;
int no_of_ssprops_sqlncli11 = -1;
int no_of_ssprops_msoledbsql = -1;
int no_of_ssprops_msoledbsql19 = -1;
// This array holds where each property set starts in gbl_init_props;
propset_info_struct init_propset_info[NO_OF_INIT_PROPSETS];
// Global pointer to OLE DB Services. Set once when we intialize, and
// never released.
IDataInitialize * data_init_ptr = NULL;
// Global pointer the OLE DB conversion library.
IDataConvert * data_convert_ptr = NULL;
// Global pointer to the IMalloc interface. Most of the time when we allocate
// memory, we rely on the Perl methods. However, there are situations when
// we must free memory allocated by SQLOLEDB. Same here, we create once, as
// the COM implementation is touted as thread-safe.
IMalloc* OLE_malloc_ptr = NULL;
// A helper routine to get default for APPNAME.
static BSTR get_scriptname () {
// Get the name of the script, taken from Perl var $0. This is used as
// the default application name in SQL Server.
SV* sv;
if (sv = get_sv("0", FALSE))
{
// Get script name into a BSTR.
BSTR tmp = SV_to_BSTR(sv);
BSTR scriptname;
WCHAR *p;
// But this name is full path, and we want only the trailing bit.
if (p = wcsrchr(tmp, '/'))
++p;
else if (p = wcsrchr(tmp, '\\'))
++p;
else if (p = wcsrchr(tmp, ':'))
++p;
else
p = tmp;
scriptname = SysAllocString(p);
SysFreeString(tmp);
return scriptname;
}
else {
return NULL;
}
}
// And another one to get the default for WSID.
static BSTR get_hostname() {
BSTR hostname = SysAllocStringLen(NULL, 31);
memset(hostname, 0, 60);
GetEnvironmentVariable(L"COMPUTERNAME", hostname, 30);
return hostname;
}
// Add a property to the global array.
// isoptoinal: properties that were added in a .X version of a provider, or
// options where we want the provider default to apply.
static void add_init_property (const char * name,
init_propsets propset_enum,
DBPROPID propid,
BOOL isoptional,
VARTYPE datatype,
BOOL default_empty,
const WCHAR * default_str,
int default_int,
int &ix)
{
// Check that we are not exceeding the global array. Note that the last
// slot must be left unusued, as this is used as a stop condition!
if (ix >= MAX_INIT_PROPERTIES - 1) {
croak("Internal error: size of array for init properties exceeded");
}
// Increment property set counter.
init_propset_info[propset_enum].no_of_props++;
strcpy_s(gbl_init_props[ix].name, INIT_PROPNAME_LEN, name);
gbl_init_props[ix].propset_enum = propset_enum;
gbl_init_props[ix].property_id = propid;
gbl_init_props[ix].isoptional = isoptional;
gbl_init_props[ix].datatype = datatype;
VariantInit(&gbl_init_props[ix].default_value);
if (! default_empty) {
gbl_init_props[ix].default_value.vt = datatype;
switch (datatype) {
case VT_BOOL :
gbl_init_props[ix].default_value.boolVal = default_int;
break;
case VT_I2 :
gbl_init_props[ix].default_value.iVal = default_int;
break;
case VT_UI2 :
gbl_init_props[ix].default_value.uiVal = default_int;
break;
case VT_I4 :
gbl_init_props[ix].default_value.lVal = default_int;
break;
case VT_BSTR :
gbl_init_props[ix].default_value.bstrVal = SysAllocString(default_str);
break;
default :
croak ("Internal error: add_init_property was called witn unhandled vartype %d",
datatype);
break;
}
}
// And increase the index.
ix++;
}
// And this is the routine that sets up the array.
static void setup_init_properties ()
{
int ix = 0;
BSTR scriptname = get_scriptname();
BSTR hostname = get_hostname();
// Init array so that all entrys are unused and init propset_info.
memset(gbl_init_props, not_in_use,
MAX_INIT_PROPERTIES * sizeof(init_property));
// DBPROPSET_DBINIT, main OLE DB init and auth properties.
init_propset_info[oleinit_props].start = ix;
init_propset_info[oleinit_props].no_of_props = 0;
add_init_property("IntegratedSecurity", oleinit_props, DBPROP_AUTH_INTEGRATED,
FALSE, VT_BSTR, FALSE, L"SSPI", NULL, ix);
add_init_property("Password", oleinit_props, DBPROP_AUTH_PASSWORD,
FALSE, VT_BSTR, TRUE, NULL, NULL, ix);
add_init_property("Username", oleinit_props, DBPROP_AUTH_USERID,
FALSE, VT_BSTR, TRUE, NULL, NULL, ix);
add_init_property("Database", oleinit_props, DBPROP_INIT_CATALOG,
FALSE, VT_BSTR, FALSE, L"tempdb", NULL, ix);
add_init_property("Server", oleinit_props, DBPROP_INIT_DATASOURCE,
FALSE, VT_BSTR, FALSE, L"(local)", NULL, ix);
add_init_property("GeneralTimeout", oleinit_props, DBPROP_INIT_GENERALTIMEOUT,
FALSE, VT_I4, FALSE, NULL, 0, ix);
add_init_property("LCID", oleinit_props, DBPROP_INIT_LCID,
FALSE, VT_I4, FALSE, NULL, GetUserDefaultLCID(), ix);
add_init_property("Pooling", oleinit_props, DBPROP_INIT_OLEDBSERVICES,
FALSE, VT_I4, FALSE, NULL, DBPROPVAL_OS_RESOURCEPOOLING, ix);
add_init_property("Prompt", oleinit_props, DBPROP_INIT_PROMPT,
FALSE, VT_I2, FALSE, NULL, DBPROMPT_NOPROMPT, ix);
add_init_property("ConnectionString", oleinit_props, DBPROP_INIT_PROVIDERSTRING,
FALSE, VT_BSTR, TRUE, NULL, NULL, ix);
add_init_property("ConnectTimeout", oleinit_props, DBPROP_INIT_TIMEOUT,
FALSE, VT_I4, FALSE, NULL, 15, ix);
// DBPROPSET_SQLSERVERDBINIT, SQLOLEDB specific proprties.
init_propset_info[ssinit_props].start = ix;
init_propset_info[ssinit_props].no_of_props = 0;
add_init_property("Appname", ssinit_props, SSPROP_INIT_APPNAME,
FALSE, VT_BSTR, FALSE, scriptname, NULL, ix);
add_init_property("Autotranslate", ssinit_props, SSPROP_INIT_AUTOTRANSLATE,
FALSE, VT_BOOL, FALSE, NULL, NULL, ix); // This property is not settable by the user, but we also force it as FALSE.
add_init_property("Language", ssinit_props, SSPROP_INIT_CURRENTLANGUAGE,
FALSE, VT_BSTR, TRUE, NULL, NULL, ix);
add_init_property("AttachFilename", ssinit_props, SSPROP_INIT_FILENAME,
FALSE, VT_BSTR, TRUE, NULL, NULL, ix);
add_init_property("NetworkAddress", ssinit_props, SSPROP_INIT_NETWORKADDRESS,
FALSE, VT_BSTR, TRUE, NULL, NULL, ix);
add_init_property("Netlib", ssinit_props, SSPROP_INIT_NETWORKLIBRARY,
FALSE, VT_BSTR, TRUE, NULL, NULL, ix);
add_init_property("PacketSize", ssinit_props, SSPROP_INIT_PACKETSIZE,
FALSE, VT_I4, TRUE, NULL, NULL, ix);
add_init_property("UseProcForPrep", ssinit_props, SSPROP_INIT_USEPROCFORPREP,
FALSE, VT_I4, FALSE, NULL, SSPROPVAL_USEPROCFORPREP_OFF, ix);
add_init_property("Hostname", ssinit_props, SSPROP_INIT_WSID,
FALSE, VT_BSTR, FALSE, hostname, NULL, ix);
add_init_property("Encrypt", ssinit_props, SSPROP_INIT_ENCRYPT,
TRUE, VT_BSTR, TRUE, NULL, NULL, ix); // Set as is_optional, to permit for different provider defaults.
// The above properties are those that are in SQLOLEDB.
no_of_ssprops_sqloledb = init_propset_info[ssinit_props].no_of_props;
// These properties were added in SQL 2005.
add_init_property("FailoverPartner", ssinit_props, SSPROP_INIT_FAILOVERPARTNER,
FALSE, VT_BSTR, TRUE, NULL, NULL, ix);
add_init_property("TrustServerCert", ssinit_props, SSPROP_INIT_TRUST_SERVER_CERTIFICATE,
FALSE, VT_BOOL, TRUE, NULL, NULL, ix);
add_init_property("OldPassword", ssinit_props, SSPROP_AUTH_OLD_PASSWORD,
FALSE, VT_BSTR, TRUE, NULL, NULL, ix);
no_of_ssprops_sqlncli = init_propset_info[ssinit_props].no_of_props;
// These two were added with SQL 2008.
add_init_property("ServerSPN", ssinit_props, SSPROP_INIT_SERVERSPN,
FALSE, VT_BSTR, TRUE, NULL, NULL, ix);
add_init_property("FailoverPartnerSPN", ssinit_props, SSPROP_INIT_FAILOVERPARTNERSPN,
FALSE, VT_BSTR, TRUE, NULL, NULL, ix);
no_of_ssprops_sqlncli10 = init_propset_info[ssinit_props].no_of_props;
// And here is a single one that made it into SQL 2012.
add_init_property("ApplicationIntent", ssinit_props, SSPROP_INIT_APPLICATIONINTENT,
FALSE, VT_BSTR, FALSE, L"ReadWrite", NULL, ix);
no_of_ssprops_sqlncli11 = init_propset_info[ssinit_props].no_of_props;
// This one appeared first with the undeprecated driver in 2018.
add_init_property("MultiSubnetFailover", ssinit_props, SSPROP_INIT_MULTISUBNETFAILOVER,
TRUE, VT_BOOL, FALSE, NULL, FALSE, ix);
add_init_property("AccessToken", ssinit_props, SSPROP_AUTH_ACCESS_TOKEN,
TRUE, VT_BSTR, TRUE, NULL, FALSE, ix);
add_init_property("Authentication", ssinit_props, SSPROP_AUTH_MODE,
TRUE, VT_BSTR, TRUE, NULL, FALSE, ix);
add_init_property("ConnectRetryCount", ssinit_props, SSPROP_INIT_CONNECT_RETRY_COUNT,
TRUE, VT_I4, FALSE, NULL, 1, ix);
add_init_property("ConnectRetryInterval", ssinit_props, SSPROP_INIT_CONNECT_RETRY_INTERVAL,
TRUE, VT_I4, FALSE, NULL, 10, ix);
add_init_property("TransparentNetworkIPResolution", ssinit_props, SSPROP_INIT_TNIR,
TRUE, VT_BOOL, FALSE, NULL, FALSE, ix);
no_of_ssprops_msoledbsql = init_propset_info[ssinit_props].no_of_props;
// Properties new in MSOLEDBSQL19.
add_init_property("HostNameInCertificate", ssinit_props, SSPROP_INIT_HOST_NAME_CERTIFICATE,
FALSE, VT_BSTR, TRUE, NULL, FALSE, ix);
add_init_property("ServerCertificate", ssinit_props, SSPROP_INIT_SERVER_CERTIFICATE,
FALSE, VT_BSTR, TRUE, NULL, FALSE, ix);
no_of_ssprops_msoledbsql19 = init_propset_info[ssinit_props].no_of_props;
// DBPROPSET_DATASOURCE, data-source properties.
init_propset_info[datasrc_props].start = ix;
init_propset_info[datasrc_props].no_of_props = 0;
add_init_property("MultiConnections", datasrc_props, DBPROP_MULTIPLECONNECTIONS,
FALSE, VT_BOOL, FALSE, NULL, FALSE, ix);
SysFreeString(scriptname);
SysFreeString(hostname);
}
// Above we leave the Encrypt option without a default, to let the provider to decide. But this
// routine permits the user to override.
void SetDefaultForEncryption(SV * sv_Encrypt,
SV * sv_Trust,
SV * sv_HostName,
SV * sv_ServerCert) {
int encrypt_ix = -1;
int trust_cert_ix = -1;
int host_name_ix = -1;
int server_cert_ix = -1;
// Loop over gbl_init_props to find the indexes for the Encrypt and TrustServerCert options
for (int ix = 0;
ix < MAX_INIT_PROPERTIES &&
(encrypt_ix < 0 || trust_cert_ix < 0 ||
host_name_ix < 0 || server_cert_ix < 0); ix++) {
if (gbl_init_props[ix].propset_enum == ssinit_props) {
if (gbl_init_props[ix].property_id == SSPROP_INIT_ENCRYPT) {
encrypt_ix = ix;
}
else if (gbl_init_props[ix].property_id == SSPROP_INIT_TRUST_SERVER_CERTIFICATE) {
trust_cert_ix = ix;
}
else if (gbl_init_props[ix].property_id == SSPROP_INIT_HOST_NAME_CERTIFICATE) {
host_name_ix = ix;
}
else if (gbl_init_props[ix].property_id == SSPROP_INIT_SERVER_CERTIFICATE) {
server_cert_ix = ix;
}
}
}
// Sanity check.
if (encrypt_ix == -1 || trust_cert_ix == -1 || host_name_ix == -1 || server_cert_ix == -1) {
croak("Internal error! Was not able to set encrypt_ix(%d), trust_cert_ix(%d), host_name_ix(%d) or server_cert_ix(%d)!\n",
encrypt_ix, trust_cert_ix, host_name_ix, server_cert_ix);
}
// Handle Encrypt option
if (sv_Encrypt && SvOK(sv_Encrypt)) {
char * setting = SvPV_nolen(sv_Encrypt);
if (strcmp("Optional", setting) == 0 ||
strcmp("Mandatory", setting) == 0 ||
strcmp("Strict", setting) == 0) {
gbl_init_props[encrypt_ix].isoptional = FALSE;
gbl_init_props[encrypt_ix].default_value.vt = VT_BSTR;
gbl_init_props[encrypt_ix].default_value.bstrVal = SV_to_BSTR(sv_Encrypt);
}
else {
warn("SetDefaultForEncrypt: Illegal value for encrypt option: '%s'.\n", setting);
croak("Permitted values are undef, 'Optional', 'Mandatory', and 'Strict'.\n");
}
}
else {
gbl_init_props[encrypt_ix].isoptional = TRUE;
VariantClear(&gbl_init_props[encrypt_ix].default_value);
}
// Handle default for TrustServerCertificate.
if (sv_Trust && SvOK(sv_Trust)) {
gbl_init_props[trust_cert_ix].isoptional = FALSE;
gbl_init_props[trust_cert_ix].default_value.vt = VT_BOOL;
gbl_init_props[trust_cert_ix].default_value.boolVal =
(SvTRUE(sv_Trust) ? -1 : FALSE);
}
else {
gbl_init_props[trust_cert_ix].isoptional = TRUE;
VariantClear(&gbl_init_props[trust_cert_ix].default_value);
}
// And host name in certificate.
if (sv_HostName && SvOK(sv_HostName)) {
gbl_init_props[host_name_ix].isoptional = FALSE;
gbl_init_props[host_name_ix].default_value.vt = VT_BSTR;
gbl_init_props[host_name_ix].default_value.bstrVal = SV_to_BSTR(sv_HostName);
( run in 0.382 second using v1.01-cache-2.11-cpan-71847e10f99 )