How Do You Call an MSSQL System Function From ADO/C++? - c++

...specifically, the fn_listextendedproperty system function in MSSQL 2005.
I have added an Extended Property to my database object, named 'schemaVersion'. In my MSVC application, using ADO, I need to determine if that Extended Property exists and, if it does, return the string value out of it.
Here is the T-SQL code that does what I want. How do I write this in C++/ADO, or otherwise get the job done?
select value as schemaVer
from fn_listextendedproperty(default, default, default, default, default, default, default)
where name=N'schemaVersion'
Here's the code I tried at first. It failed with the error listed below the code:
_CommandPtr cmd;
cmd.CreateInstance(__uuidof(Command));
cmd->ActiveConnection = cnn;
cmd->PutCommandText("select value "
"from fn_listextendedproperty(default, default, default, default, default, default, default) "
"where name=N'schemaVersion'");
VARIANT varCount;
cmd->Execute(NULL, NULL, adCmdText);
...here are the errors I peeled out of the ADO errors collection. The output is from my little utility function which adds the extra text like the thread ID etc, so ignore that.
(Proc:0x1930, Thread:0x8A0) INFO : === 1 Provider Error Messages : =======================
(Proc:0x1930, Thread:0x8A0) INFO : [ 1] (-2147217900) 'Incorrect syntax near the keyword 'default'.'
(Proc:0x1930, Thread:0x8A0) INFO : (SQLState = '42000')
(Proc:0x1930, Thread:0x8A0) INFO : (Source = 'Microsoft OLE DB Provider for SQL Server')
(Proc:0x1930, Thread:0x8A0) INFO : (NativeError = 156)
(Proc:0x1930, Thread:0x8A0) INFO : ==========================================================
EDIT: Updated the call according to suggestions. Also changed "SELECT value AS schemaVer" to just "SELECT value".
EDIT: Changed the first parameter of Execute() to NULL per suggestion. This fixed my original problem, and I proceeded to the next. :)

Try specifying NULL rather than default for each parameter of fn_listextendedproperty. This should hopefully then execute without errors, just leaving you to retrieve the result as your next step.

I still have not figured out how to do this directly. To get on with my life, I wrote a stored procedure which called the function:
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[mh_getSchemaVersion]
#schemaVer VARCHAR(256) OUTPUT
AS
select #schemaVer = CAST( (select value from fn_listextendedproperty(default, default, default, default, default, default, default) where name=N'schemaVersion') AS varchar(256) )
return ##ROWCOUNT
...and then called thst sproc from my ADO/C++ code:
_CommandPtr cmd;
cmd.CreateInstance(__uuidof(Command));
cmd->ActiveConnection = cnn;
cmd->PutCommandText("mh_getSchemaVersion")_l
_variant_t schemaVar;
_ParameterPtr schemaVarParam = cmd->CreateParameter("#schemaVer", adVarChar, adParamOutput, 256);
cmd->GetParameters()->Append((IDispatch*)schemaVarParam);
cmd->Execute(NULL, NULL, adCmdStoredProc);
std::string v = (const char*)(_bstr_t)schemaVarParam->GetValue();
ver->hasVersion_ = true;
...which works, but I didn't want to have to deploy a new stored procedure.
So if anyone can come up with a solution to the original problem and show me how to call the system function directly from ADO/C++, I will accept that as the answer. Otherwise I'll just accept this.

Related

GetHostedProfilePage not honouring hostedProfileBillingAddressOptions setting

I've been trying to update our API call to the CIM interface for Authorize.net to hide the Billing Address fields on the hosted profile page.
The documentation states that when call the token creation function, passing in a setting "hostedProfileBillingAddressOptions" with a value of "showNone" will hide the billing address part of the form, however when I pass in this setting I am still getting the billing address showing.
I've verified that I'm passing the setting correctly (added the same way as the "hostedProfileIFrameCommunicatorUrl" and "hostedProfilePageBorderVisible" settings) and if I pass an invalid value for the "hostedProfileBillingAddressOptions" option, the Token creation function will return an error
Is there something else that this option is dependent on, such as an account setting or another settings parameter?
For reference, I'm testing this in the Sandbox system and I'm using the dotNet SDK, my test code for calling the API function is as follows
Public Shared Function CreateHostFormToken(apiId As String, apiKey As String, branchId As Int64, nUser As Contact, iframeComURL As String) As String
Dim nCustProfile = GetCustomerProfile(apiId, apiKey, branchId, nUser)
Dim nHost = New AuthorizeNet.Api.Contracts.V1.getHostedProfilePageRequest()
nHost.customerProfileId = nCustProfile
' Set Auth
Dim nAuth = New Api.Contracts.V1.merchantAuthenticationType()
nAuth.ItemElementName = Api.Contracts.V1.ItemChoiceType.transactionKey
nAuth.name = apiId
nAuth.Item = apiKey
nHost.merchantAuthentication = nAuth
' Set Params
Dim settingList As New List(Of Api.Contracts.V1.settingType)
Dim nParam As New Api.Contracts.V1.settingType With {.settingName = "hostedProfileIFrameCommunicatorUrl",
.settingValue = iframeComURL}
settingList.Add(nParam)
nParam = New Api.Contracts.V1.settingType With {.settingName = "hostedProfilePageBorderVisible",
.settingValue = "false"}
settingList.Add(nParam)
nParam = New Api.Contracts.V1.settingType With {.settingName = "hostedProfileBillingAddressOptions",
.settingValue = "showNone"}
settingList.Add(nParam)
nHost.hostedProfileSettings = settingList.ToArray
Dim nX = New AuthorizeNet.Api.Controllers.getHostedProfilePageController(nHost)
Dim nRes = nX.ExecuteWithApiResponse(GetEnvironment())
Return nRes.token
End Function
I've looked through the SDK code as well, and I don't see anything there that would be preventing the setting from being passed through.
Has anyone come across this issue, or successfully set the card entry form to hide the billing address?
There turned out to be two parts to the solution to this problem:
In order to use the "hostedProfileBillingAddressOptions" option, you need to use a newer version of the capture page than I was using. I was using "https://secure2.authorize.net/profile/", while the new version is "https://secure2.authorize.net/customer/". Added bonus, the new URL provides a much nicer and modern looking form.
However, once this was working, I then had the problem that on entering the card, a validation message told me that "address and Zip code are required", despite not being visible. I did also make sure that I had the option "hostedProfileBillingAddressRequired" set to false (which is it's default value anyway)
The response from Authorize.net support is that in order to capture card without an address, the option "hostedProfileValidationMode" must be set to "testMode".
This is not mentioned in the documentation (at least as far as I could see), so may not be something that other people are aware of since it is a little counter-intuitive to use 'testMode' on a live environment.
It's not ideal since validating the card for a customer account will send a transaction email to the merchant, but it seems there is not another way around this just now.
In summary, to allow the customer to add a credit card to their profile without having to provide an address, you need to specify the following options:
Form URL for capture - https://secure2.authorize.net/customer/
getHostedProfilePageRequest -
hostedProfileIFrameCommunicatorUrl: *your URL*
hostedProfilePageBorderVisible: false //assuming you are using an iFrame
hostedProfileValidationMode: testMode
hostedProfileBillingAddressOptions: showNone

Unparsable MOF Query When Trying to Register Event

Update 2
I accepted an answer and asked a different question elsewhere, where I am still trying to get to the bottom of this.
I don't think that one-lining this query is the answer, as I am still not getting the required results (and multi-lining queries is allowed in .mof, as shown in the URLs in comments to the answer ...
Update
I rewrote the query as a one-liner as suggested, but still got the same error! As it was still talking about lines 11-19 I knew there must be another issue. After saving a new file with the change, I reran mofcomp and it appears to have loaded, but the event which I have subscribed to simply does not work.
I really feel that there is not enough documentation on this topic and it is hard to work out how I am meant to debug this - any help on this would be much appreciated, even if this means using a different more appropriate method.
I have the following .mof file, which I would like to use to register an event on my system :
#pragma namespace("\\\\.\\root\\subscription")
instance of __EventFilter as $EventFilter
{
Name = "Event Filter Instance Name";
Query = "Select * from __InstanceCreationEvent within 1 "
"where targetInstance isa \"Cim_DirectoryContainsFile\" "
"and targetInstance.GroupComponent = \"Win32_Directory.Name=\"c:\\\\test\"\"";
QueryLanguage = "WQL";
EventNamespace = "Root\\Cimv2";
};
instance of ActiveScriptEventConsumer as $Consumer
{
Name = "TestConsumer";
ScriptingEngine = "VBScript";
ScriptText =
"Set objFSO = CreateObject(\"Scripting.FileSystemObject\")\n"
"Set objFile = objFSO.OpenTextFile(\"c:\\test\\Log.txt\", 8, True)\n"
"objFile.WriteLine Time & \" \" & \" File Created\"\n"
"objFile.Close\n";
// Specify any other relevant properties.
};
instance of __FilterToConsumerBinding
{
Filter = $EventFilter;
Consumer = $Consumer;
};
But whenever I run the command mfcomp myfile.mof I am getting this error:
Parsing MOF file: myfile.mof
MOF file has been successfully parsed
Storing data in the repository...
An error occurred while processing item 1 defined on lines 11 - 19 in file myfile.mof:
Error Number: 0x80041058, Facility: WMI
Description: Unparsable query.
Compiler returned error 0x80041058
This error appears to be caused by incorrect syntax in the query, but I don't understand where I have gone wrong with this - is anyone able to advise?
There are no string concatenation or line continuation characters being used in building "Query". To keep it simple, you could put the entire query on one line.

QtSqlQuery next/first returns false

I have what I think is a very simple case, but I don't understand why it fails.
Database used is sqlite3, linux platform. Qt 5.3.
I have this table: CREATE TABLE db_info (name TEXT, value TEXT);
Containing this data (output from sqlite3 client):
version|1
created|2015-01-16 11:06:12
Yes, it's very simple.
The purpose is to check if the DB is created with another version of the application. So I compare the version in the DB with a compiled constant in the code.
Thus, during startup, I do this (trimmed for brevity):
_db = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE", "mydb"));
_db->setDatabaseName(dbFile);
_db->open();
QSqlQuery query(*_db);
query.prepare("SELECT value FROM db_info WHERE name = 'version' AND value = :version");
query.bindValue(":version", DB_VERSION);
query.exec();
if(query.first())
// same version
else
// some other version
Not very complicated stuff...
Now to the specific problem:
_db->open() returns true
query.prepare() returns true
query.isSelect() returns true
query.exec() returns true
After exec():
query.isActive() returns true
query.size() returns -1
query.first() or query.next() returns false
What could be the problem?
According to the dox (http://doc.qt.io/qt-5/qsqlquery.html#first), first() returns false if the query is not active or it's not a select, so that can't be it.
But I guess, since size() returns -1 there definitely is something amiss somewhere...
I've tried adding some calls to lastError() but it's always empty. Both from query and from _db. It there some other means of getting some mesages from the database, or driver or some such?
I've also tried removing the WHERE clause. No difference.
Running the exact same query in the sqlite3 client works fine.

WMI GetStringValue Returns Null for added registry values

I'm going a little crazy here. I am trying to read the value of a registry string value I manually created and every time it returns a null. If I try to read the value of an existing registry string value, it returns the value just fine. Here is the code I'm using:
ManagementBaseObject rinParams = registry.GetMethodParameters("GetStringValue");
rinParams["hDefKey"] = HKEY_LOCAL_MACHINE;
rinParams["sSubKeyName"] = #"SOFTWARE\Microsoft\.NetFramework";
// rinParams["sValueName"] = "InstallRoot";
rinParams["sValueName"] = "test";
ManagementBaseObject routParams = registry.InvokeMethod("GetStringValue", rinParams, null);
if (routParams.Properties["sValue"].Value != null)
{
routput = routParams.Properties["sValue"].Value.ToString();
}
What I did was set the code to use the above code to read the value of the "InstallRoot" in the registry HKEY_LOCAL_Machine\SOFTWARE\Microsoft.NetFramework\InstallRoot which is a REG_SZ value. I get a successful read and the directory path is returned just fine. I then created another REG_SZ variable name "test" in the same .NetFramework key and commented out the "sValueName" = "InstallRoot" and replaced it with a line for "sValueName" = "test". When I run this code under the debugger, I get a return value of null.
I've tried adding keys under SOFTWARE and values in that key like SOFTWARE\Testkey and I get the same result every time. It will not let me read a key I create, it always returns null, but it seems like I can read any key that already existed. I don't understand why I'm getting this result.
An FYI, is that I am doing a remote registry read from a Windows 7 PC. My ultimate goal is to be able to add registry keys and values. I've tried to do that and I always get an error exception "Not Found" when I try that, so I'm trying to get down to the easiest thing possible, which is to read a key and even that's not working. Any ideas for what might be going on here?
This is how I'm making the remote connection to the Windows 2008r2 server to read the registry:
ConnectionOptions connectoptions = new ConnectionOptions();
connectoptions.Impersonation = ImpersonationLevel.Impersonate;
connectoptions.Authentication = AuthenticationLevel.PacketPrivacy;
connectoptions.Username = "administrator";
connectoptions.Password = **password redacted**
ManagementScope scope = new ManagementScope(#"\\" + systemIP + #"\root\default");
scope.Options = connectoptions;
ManagementClass registry = new ManagementClass(scope, new ManagementPath("StdRegProv"), null);

Null Reference Excepion when saving data on subsonic 3

I am testing subsonic 3, i can query my database but when i am inserting a record i have an exception. Here is my code:
Client lClient = new Client();
lClient.Name = "Peter";
lClient.FullName = "Richards";
lCliente.Save();
And i have a null reference exception on this generated code:
var newKey=_repo.Add(this,provider);
Any help is appreciated.
I am using ActiveRecords
I had a similar problem, with code not unlike the following:
var pending = myTable.SingleOrDefault(x => x.Id == 1);
if (pending == null)
pending = new myTable();
pending.Id = 1;
pending.MyDate = DateTime.Now;
pending.MyString = someString;
pending.Save();
This worked the first time I ran it, on an empty table, but not the second time when updating. I got a nullreference exception somewhere inside the subsonic repository. The solution was to add a primary key, as Rob suggested.
Just thought I'd mention it (thanks Rob).
Where does the null reference exception actually happen? Is _repo null?
Try and double check that you don’t have any columns in the “Client” table which are not nullable and you don’t set any value.
Also make sure you PK is handled correctly (check you have the [Property.IsForeignKey=true;] attribute)
Do you have NullReferenceException Checked in (file menu) Debug -> Exceptions (press Find and type NullReferenceException, press OK)?
I downloaded the SubSonic code and used it as reference for my project, the exception is thrown in SubSonic.Core\Repository\SubSonicRepository.cs:209 because prop is not checked for null at line 208, and any exceptions are swallowed as evidenced by line 213.
What happens is visual studio breaks on all the exceptions checked in the mentioned dialog. So in one way, this is the expected behaviour from the code.
What actually causes prop to become null, in my case, the table field name is lower-case, but the property is actually cased properly.
From Immediate:
tbl.PrimaryKey.Name
"playerinformationid"
item.GetType().GetProperties()
{System.Reflection.PropertyInfo[11]}
[0]: {System.Collections.Generic.IList`1[SubSonic.Schema.IColumn] Columns}
// *snip*
[5]: {Int32 PlayerInformationid}
// *snip*
item.GetType().GetProperty("PlayerInformationid")
{Int32 PlayerInformationid} // Works!
item.GetType().GetProperty(tbl.PrimaryKey.Name)
null
I hacked this together to "just make it work" (Warning: newbie at 3.5 stuff)
-var prop = item.GetType().GetProperty(tbl.PrimaryKey.Name);
+var lowerCasedPrimaryKeyName = tbl.PrimaryKey.Name.ToLowerInvariant();
+var prop = item.GetType().GetProperties().First<System.Reflection.PropertyInfo>(x => x.Name.ToLowerInvariant() == lowerCasedPrimaryKeyName);
Does your table have a PrimaryKey? It doesn't sound like it does. If not - this is your problem.