I'm using SQLite (3.6.4) from a C++ application (using the standard C api). My question is: once a query has been prepared, using sqlite3_prepare_v2(), and bound with parameters using sqlite3_bind_xyz() - is there any way to get a string containing the original SQL query?
The reason is when something goes wrong, I'd like to print the query (for debugging - this is an in-house developer only test app).
Example:
sqlite3_prepare_v2(db, "SELECT * FROM xyz WHERE something = ? AND somethingelse = ?", -1, &myQuery, NULL);
sqlite3_bind_text(myQuery, 1, mySomething);
sqlite3_bind_text(myQuery, 2, mySomethingElse);
// ....
// somewhere else, in another function perhaps
if (sqlite3_step(myQuery) != SQLITE_OK)
{
// Here i'd like to print the actual query that failed - but I
// only have the myQuery variable
exit(-1);
}
Bonus points if it could also print out the actual parameters that was bound. :)
You probably want to use sqlite3_trace
This will call a callback function (that you define) and on of the parameters is a char * of the SQL of the prepared statements (including bound parameters).
As per the comments in sqlite3.c (amalgamation), sqlite3_sql(myQuery) will return the original SQL text.
I don't see any function for finding the value bound at a particular index, but we can easily add one to the standard set of SQLite functions. It may look something like this:
const char* sqlite3_bound_value(sqlite3_stmt* pStmt, int index)
{
Vdbe *p = (Vdbe *)pStmt;
// check if &p->aVar[index - 1] points to a valid location.
return (char*)sqlite3ValueText(&p->aVar[index - 1], SQLITE_UTF8);
}
Well, the above code shows only a possible way sqlite3_bound_value() could be implemented. I haven't tested it, it might be wrong, but it gives certain hints on how/where to start.
Quoting the documentation:
In the "v2" interfaces, the prepared statement that is returned (the sqlite_stmt object) contains a copy of the original SQL text.
http://www.sqlite.org/c3ref/prepare.html
Related
There is a great MongoDb C++ Driver. The only thing that makes it hard for newbies like me to use it - is the lack of teeny-weeny examples. For instance, I know there is a method called getCollectionNames, but I'm not sure how to use it. In Python I would do it like this:
db = MongoClient(host, port)[db_name]
colls = db.collection_names()
and I'm done. But I don't feel so comfortable with C++ and can not figure out myself how to convert raw function declarations in documentation to some working code.
So, this is what I've done by now and see that it works:
ConnectionString cs = ConnectionString::parse(uri, errmsg);
DBClientBase * conn(cs.connect(errmsg));
Now I want to make one step further and get all collection names. Please, give some advice.
EDIT
Well, I found a method somewhere in dbclientinterface.h called getCollectionNames. It is defined like so:
std::list<std::string> getCollectionNames( const std::string& db,
const BSON& filter = BSONObj())
But I find this sole declaration without any informative hints completely useless. It is just a sum of letters and no more.
EDIT
I found a solution and I will post it below.
This is the solution:
std::string uri = "mongodb://127.0.0.1:27017/mydb";
std::string errmsg;
ConnectionString cs = ConnectionString::parse(uri, errmsg);
DBClientBase * conn(cs.connect(errmsg));
std::list<std::string> colls = conn->getCollectionNames("mydb");
for(std::list<std::string>::iterator it = colls.begin();it != colls.end();++it){
do_something(*it);
}
I'm using ADO to communicate with my Sybase server..
This is how I'm executing a simple command:
_ConnectionPtr m_ConnPtr;
//... Instantiate connection
_CommandPtr m_CommPtr;
m_CommPtr->CreateInstance(__uuidof(Command))
m_CommPtr->ActiveConnection = m_ConnPtr;
Variant m_variant;
m_variant.SetString("My Param Value");
_ParameterPtr ParamPtr;
ParamPtr = m_CommPtr->CreateParameter("#StrParam", (DataTypeEnum) m_variant.vt, adParamInput, NULL, m_variant);
m_CommPtr->Parameters->Append(PrmPtr);
m_CommPtr->CommandText = "EXECUTE my_stored_procedure #StrParam";
m_CommPtr->Execute(NULL, NULL, adOptionUnspecified);
#StrParam is supposed to be a VarChar type..
Running this gives me an error:
Attempt to insert NULL value into column 'StrParam'. table 'MYTABLE';
column does not allow nulls. Update fails.
I'm not sure why I'm getting this error, since I am specifiying its value ("My Param Value")..
Does anyone know what I'm doing wrong?
(I didn't include the Stored procedure,, because I'm sure there's nothing wrong with the procedure itself.. Other application using the same procedure works fine. So there must be something wrong with how I'm using the parametized command)
I have no clue what your Variant class even is. But the traditional variant type (vt) and the ADO data type are not synonymous. Second, you're not setting up the call nor parameters correctly for a typical stored-proc invoke.
Below is how you would do this using a standard stored proc call and variant_t from the comutil library:
_CommandPtr m_CommPtr(__uuidof(Command));
m_CommPtr->ActiveConnection = m_ConnPtr;
m_CommPtr->CommandType = adoCmdStoredProc;
m_CommPtr->CommandText = L"my_stored_procedure";
// setup parameter
variant_t vParam = L"My Param Value";
_ParameterPtr ParamPtr = m_CommPtr->CreateParameter(L"#StrParam", adBSTR, adParamInput, 0, vParam);
m_CommPtr->Parameters->Append(ParamPtr);
m_CommPtr->Execute(NULL, NULL, adOptionUnspecified);
Note that the ParamPtr is generally optional and you can straight-away append the parameter to the command's Parameters collection if you don't need it for anything else, like this:
m_CommPtr->Parameters->Append(m_CommPtr->CreateParameter(
L"#StrParam", adBSTR, adParamInput, 0, vParam));
The method you're using is common for parameters that are both input and output, as you retain the parameter object reference to extract the output side of the parameter. I see no evidence of that in your call, which is the only reason I mention it here.
Also note that unless the command returns rows for a result set you should also invoke with adExecuteNoRecords for the execution third option (which is typical for many fire-and-forget stored procedure executions)
Finally, the names of the parameters are not important unless you use the NamedParameters property of the command object. This is commonly done when you have additional parameters with default values that you would like to retain, setting only specific parameters as part of your append list.
Best of luck.
I'm wondering whether anyone else has had this problem and how they resolved it?
Our application makes the follwoing ODBC call:
CString strCmd = "sprTestSingleSelect";
rc = SQLExecDirect(hstmt, (UCHAR*)(LPCSTR)strCmd, SQL_NTS);
The call retruns SQL_SUCCESS_WITH_INFO. By checking SQLGetDiagRec we see the message; Cursor type changed.
We found the following articles from Micrsoft;
http://support.microsoft.com/kb/156500/en-us
http://msdn.microsoft.com/library/ms130807.aspx
The stored procedure, sprTestSingleSelect, was created specifically to test what both articles hinted at - multiple selects cause the change.
CREATE PROCEDURE sprTestSingleSelect
AS
BEGIN
SET NOCOUNT ON;
SELECT id, firstname, lastname FROM address
END
GO
However, even with this very simple (single SELECT) stored procedure, the cursor type is still being changed (from SQL_CURSOR_KEYSET_DRIVEN to SQL_CURSOR_FORWARD_ONLY).
We need to cursor type to stay at SQL_CURSOR_KEYSET_DRIVEN, as later on in the application we are calling SQLFetchScroll(hstmt, SQL_FETCH_LAST, 0);, which is falling because of the incorrect cursor type.
Does anyone have an idea of what we might be doing wrong or what is going wrong?
We are using MS SQL Server 2008R2
Our application is written in C++ (using Visual Studio 10 Premium)
We've managed to get the above test working, however the solution is not very satisfactory.
When the store procedure only contains a single SELECT statement and nothing else it works. So to get it working all we had to do was remove the statement SET NOCOUNT ON;. As a side note, we tested setting NOCOUNT to OFF which also didn't work - removing the statement alltogether is what was required.
This seems to make using stored procedures to return data (result sets) rather useless!
If anyone has another (better) solution, we'd love to hear it...
In my C++ app, I have a string which contains XML data. Let's say I have an attribute Number1 and an attribute Number2.
I want to send that string to a Lua script and have it return a modified XML string. Let's say it adds a new attribute Product with the value of Number1 and Number2.
Is that easily done using C++/Lua, and if so how?
There are several methods to work with XML data listed at the Lua Users Wiki. The better options involve calls back to C (e.g. LuaXML and LuaExpat) so this only makes sense to do if there are other reasons to use Lua beyond just parsing XML.
Not a Lua user myself...but just browsing the documentation, it seems that you can use lua_pushstring() to put a copy of a null-terminated C string into the Lua stack:
http://pgl.yoyo.org/luai/i/lua_pushstring
Although there is no specific definition for things like lua_popstring() you can define something like that yourself:
std::string lua_popstring(lua_State *L)
{
std::string tmp = lua_tostring(L, lua_gettop(L));
lua_pop(L, 1);
return tmp;
}
With that in hand you should be able to modify the standard example for passing data into Lua and getting a result back for your purpose:
http://lua-users.org/wiki/SimpleLuaApiExample
You could do it similar to this (not this might not be 100 % correct due to being out of my mind and it doesn't include error handling):
lua_getglobal(L, "modifyXml"); // push function on stack by name
lua_pushstring(L, xml); // push the xml string as parameter
lua_pcall(L, 1, 1, 0); // call the function with 1 parameter, 1 return value and no error handler
strcpy(xml, lua_tostring(L, -1)); // get the top of the stack as a string and copy it to xml
lua_pop(xml, 1); // remove the string from the stack
The lua function called could look like this:
function modifyXml(xml)
-- do something with xml here
return xml
end
If you use Luabind it could look something like this in C++:
std::string result = luabind::call_function<std::string>(
"yourLuaFunction", inputXmlString);
You would implement yourLuaFunction in Lua of course, and require that Lua module from within your C++ program.
I'm using SQLite (3.6.4) from a C++ application (using the standard C api). My question is: once a query has been prepared, using sqlite3_prepare_v2(), and bound with parameters using sqlite3_bind_xyz() - is there any way to get a string containing the original SQL query?
The reason is when something goes wrong, I'd like to print the query (for debugging - this is an in-house developer only test app).
Example:
sqlite3_prepare_v2(db, "SELECT * FROM xyz WHERE something = ? AND somethingelse = ?", -1, &myQuery, NULL);
sqlite3_bind_text(myQuery, 1, mySomething);
sqlite3_bind_text(myQuery, 2, mySomethingElse);
// ....
// somewhere else, in another function perhaps
if (sqlite3_step(myQuery) != SQLITE_OK)
{
// Here i'd like to print the actual query that failed - but I
// only have the myQuery variable
exit(-1);
}
Bonus points if it could also print out the actual parameters that was bound. :)
You probably want to use sqlite3_trace
This will call a callback function (that you define) and on of the parameters is a char * of the SQL of the prepared statements (including bound parameters).
As per the comments in sqlite3.c (amalgamation), sqlite3_sql(myQuery) will return the original SQL text.
I don't see any function for finding the value bound at a particular index, but we can easily add one to the standard set of SQLite functions. It may look something like this:
const char* sqlite3_bound_value(sqlite3_stmt* pStmt, int index)
{
Vdbe *p = (Vdbe *)pStmt;
// check if &p->aVar[index - 1] points to a valid location.
return (char*)sqlite3ValueText(&p->aVar[index - 1], SQLITE_UTF8);
}
Well, the above code shows only a possible way sqlite3_bound_value() could be implemented. I haven't tested it, it might be wrong, but it gives certain hints on how/where to start.
Quoting the documentation:
In the "v2" interfaces, the prepared statement that is returned (the sqlite_stmt object) contains a copy of the original SQL text.
http://www.sqlite.org/c3ref/prepare.html