oledb: INSERT with OUTPUT statement generates DB_E_ERRORSOCCURRED error - c++

I'm creating a small c++ library to access MS SQL Server database using OLE DB (with cpp wrapper provided by atldbcli).
While SELECT or INSERT statements alone works fine I've encountered problem with SQL query like:
INSERT INTO testTable(col_int, col_str)
OUTPUT INSERTED.autincPK --output primary key value, required for further processing
VALUES (43, 'test str')
Produce error:
DB_E_ERRORSOCCURRED Multiple-step OLE DB operation generated errors. Check each OLE DB status value, if available. No work was done.
I'm unable to find more error info.
Query executes without any errors in database. Error message says 'No work was done' but new row is created in table (autocommit is enabled).
The relevant code looks like:
#include <atldbcli.h>
int execSQL(CSession *pSession, const std::string& sql)
{
CCommand<CDynamicAccessor, CRowset, CMultipleResults> command;
CDBPropSet rgPropertySet[1] = {};
rgPropertySet[0].SetGUID(DBPROPSET_ROWSET);
rgPropertySet[0].AddProperty(DBPROP_CANSCROLLBACKWARDS, true);
rgPropertySet[0].AddProperty(DBPROP_CANFETCHBACKWARDS, true);
rgPropertySet[0].AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT);
rgPropertySet[0].AddProperty(DBPROP_IMultipleResults, true);
}
HRESULT hr = command.Open(*pSession, sql.c_str(), rgPropertySet, &m_rowsAffected, DBGUID_DEFAULT, false, 1ul);
if (FAILED(hr)){
//error handling
}
return 0;

Related

'Invalid schema name' error thrown by Doctrine, but the raw SQL seems to work

I'm using some custom DQL functions to filter rows by some JSONB fields in PostgreSQL. Here's my query function:
private function findTopLevelResources(): array {
return $this->createQueryBuilder('r')
->where("JSON_EXISTS(r.contents, '-1') = FALSE")
->getQuery()
->getResult();
}
Running this code results in DriverException from AbstractPostgreSQLDriver:
An exception occurred while executing 'SELECT r0_.id AS id_0, r0_.marking AS marking_1, r0_.contents AS contents_2, r0_.kind_id AS kind_id_3 FROM resource r0_ WHERE r0_.contents?'-1' = false':
SQLSTATE[3F000]: Invalid schema name: 7 ERROR: schema "r0_" does not exist
LINE 1: ... r0_.kind_id AS kind_id_3 FROM resource r0_ WHERE r0_.conten...
^
I tried to execute the raw SQL query manually from PHPStorm and it worked, no errors.
How do I get this to work in Doctrine?
Why doesn't this query work with Doctrine, but does when I test it manually?
Here's JSON_EXISTS: (based on syslogic/doctrine-json-functions)
class JsonExists extends FunctionNode
{
const FUNCTION_NAME = 'JSON_EXISTS';
const OPERATOR = '?';
public $jsonData;
public $jsonPath;
public function getSql(SqlWalker $sqlWalker)
{
$jsonData = $sqlWalker->walkStringPrimary($this->jsonData);
$jsonPath = $this->jsonPath->value;
return $jsonData . self::OPERATOR . "'$jsonPath'";
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->jsonData = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$this->jsonPath = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
Registered via Symfony's YAML config like this:
doctrine:
orm:
dql:
numeric_functions:
json_exists: Syslogic\DoctrineJsonFunctions\Query\AST\Functions\Postgresql\JsonExists
Versions of stuff:
PHP 7.1.1
doctrine/dbal v2.6.1
doctrine/orm dev-master e3ecec3 (== 2.6.x-dev)
symfony/symfony v3.3.4
The error message is a false clue.
Actual problem is caused by PDO (this is why it works from PHPStorm). When it sees a query like this:
SELECT * FROM foo WHERE contents?'bar'
It treats it like a parametrized query and the question mark ? as a parameter. For some reason it sometimes results in nonsensical error messages. This specific case could be solved by adding a space after the question mark, but it won't work for operators ?| and ?& which can't have a space in the middle.
The solution is to use functions corresponding to operators (this question saved the day). One can find out how they are called using queries like this one:
SELECT oprname, oprcode FROM pg_operator WHERE oprname IN ('?', '?|', '?&')
Here's the part of result related to JSON:
? → jsonb_exists
?| → jsonb_exists_any
?& → jsonb_exists_all
So instead of previous query which causes problems via PDO, one can use this equivalent one:
SELECT * FROM foo WHERE jsonb_exists(contents, 'bar')

Can't retrieve identity field after insert in sql database

Using C++ Qt framework and sql server 2008 I've been trying to insert a record into a table with an identity field and retrieve the identity value. Below is a simplified code sample which actually does do the insert but just doesn't retreive the identity. The identity returned from query.value(0) is an invalid QVariant.
QSqlQuery query(*pConn);
query.prepare("insert into [VH_MANUFACTURER] values ('sRRS test man code','RRS type','RRS logo file',1,'RRS SEO para','RRS description','RS');"
"select SCOPE_IDENTITY();");
if(query.exec())
{
if(query.next())
{
QVariant identity = query.value(0);
int id=identity.toInt();
}
}
I've tried using select ##identity instead of scope_identity with no improvement and also QSqlQuery .lastInsertId() which also returns an invalid QVariant, see below.
bool bFeature = pConn->driver()->hasFeature(QSqlDriver::LastInsertId);
QSqlQuery query(*pConn);
query.prepare("insert into [VH_MANUFACTURER] ([MFG_NAME],[MFG_TYPE],[MFG_LOGO],[MFG_ACTIVE],[MFG_SEO_CONTENT],[MFG_DESCRI],[MFG_CAPMANCODE]) values ('sRRS test man code','RRS type','RRS logo file',1,'RRS SEO para','RRS description','RS')");
if(query.exec())
{
QVariant id=query.lastInsertId();
}
hasFeature returns true, so the driver is supposed to support what I'm trying to do.
Just to test the sql , I ran the sql directly through Sql Server Management Studio and it inserts as expected and returns the identity value correctly.
Finally found a work around using OUTPUT clause in sql. I don't exactly know why the other methods I tried don't work. There is a sql server bug associated with this feature but that doesn't explain why it worked in ssms but not in c++ Qt code. The sample below show's the work around. Here's the reference I used to solve this.
bool bFeature = pConn->driver()->hasFeature(QSqlDriver::LastInsertId);
QSqlQuery query(*pConn);
query.prepare("insert into [VH_MANUFACTURER] ([MFG_NAME],[MFG_TYPE],[MFG_LOGO],[MFG_ACTIVE],[MFG_SEO_CONTENT],[MFG_DESCRI],[MFG_CAPMANCODE]) OUTPUT INSERTED.MFG_ID values ('sRRS test man code','RRS type','RRS logo file',1,'RRS SEO para','RRS description','RS')");
if(query.exec())
{
if(query.next())
{
QVariant id=query.value("MFG_ID");
}
}

Qt and SQLite, error when executing query, without error message

I am using Qt 5.4 and SQLite to to database operations, all other requests work, but this one doesn't seem to work and gives no error.
QSqlQuery query(Globals::db);
QString cmd = "Update VideoFile set isVisible = 0 WHERE Id =1;";
if(query.prepare(cmd))
qDebug("Prepare success..."); //<-- prints out
if (!query.exec()) {
qDebug("Error occurred querying.");
qDebug("%s.", qPrintable(Globals::db.lastError().text())); //<<-- prints out blank
}
Tried so far:
o) Database: exists!
o) Query Prepare() yields True
o) When executing the same Statement in SQLite Browser. Works!
i read about a problem here:, that some databases have a certain delay.
"Portability note: Some databases choose to delay preparing a query until it is executed the first time. In this case, preparing a syntactically wrong query succeeds, but every consecutive exec() will fail." But apparently, the query is not syntactically wrong.

Schema validation difference between BizTalk IDE and XmlReader

I'm trying to get into unit tests for a BizTalk application I'm working on, following the example in Michael Stephensons blog post and seemed to be getting somewhere
Then I got an error down the line, which I tracked back to a "invalid" XML test file I was using, but this was passing my validation against schema unit test ...
- reason being incorrect namespace
My puzzlement is why does the XmlReader think the XML is valid vs. the schema, but if I use the BizTalk IDE "Validate Instance" option I get the errors ...
... error BEC2004: Validate Instance failed for schema FromFrontOffice.xsd, file: ...
XmlSchema schema = XmlSchema.Read(schemaStream, null);
XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
xmlReaderSettings.Schemas.Add(schema);
xmlReaderSettings.ValidationType = ValidationType.Schema;
xmlReaderSettings.ValidationEventHandler += ValidationEventHandler;
XmlReader xmlReader = XmlReader.Create(xmlStream, xmlReaderSettings);
while (xmlReader.Read())
private void ValidationEventHandler(object sender, ValidationEventArgs args)
{
if (args.Exception == null) return;
_IsValid = false;
}
Think I've sorted it ... trick seems to be using ValidationFlags
xmlReaderSettings.ValidationFlags =
XmlSchemaValidationFlags.ReportValidationWarnings |
XmlSchemaValidationFlags.ProcessIdentityConstraints |
XmlSchemaValidationFlags.ProcessInlineSchema |
XmlSchemaValidationFlags.ProcessSchemaLocation;

How Do You Call an MSSQL System Function From ADO/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.