Why Isn't find_one working in MongoDB C++? - c++

I have a MongoDB 3.0.7 database, created with the mongo shell. The following works fine:
% mongo test
> vs = db.myCollection.findOne({"somefield.subfield": "somevalue"})
but when I do this in C++:
mongocxx::instance inst{};
mongocxx::client conn{};
auto db = conn["test"];
bsoncxx::stdx::optional< bsoncxx::document::value> docObj;
try {
docObj =
db["myCollection"]
.find_one(document{} <<
"somefield.subfield" << "someValue" <<
bsoncxx::builder::stream::finalize);
} catch (mongocxx::exception::operation e) {
std::cerr << "Retrieval failed (and exception thrown)";
}
if (docObj == bsoncxx::stdx::nullopt)
std::cerr << "Failed to find object";
I get "Failed to find object". What am I missing here?
Update: 11/23/2015, 10:00
I've installed the latest cxx driver (0.3.0), and made the following changes:
mongocxx::instance inst{};
mongocxx::client *connPtr;
bsoncxx::stdx::string_view connectionString("mongodb://localhost");
connPtr = new mongocxx::client(mongocxx::uri(connectionString));
auto db = connPtr->database("test");;
bsoncxx::stdx::optional< bsoncxx::document::value> docObj;
try {
docObj =
db["myCollection"]
.find_one(document{} <<
"somefield.subfield" << "someValue" <<
bsoncxx::builder::stream::finalize);
} catch (mongocxx::exception::operation e) {
std::cerr << "Retrieval failed (and exception thrown)";
}
if (docObj == bsoncxx::stdx::nullopt)
std::cerr << "Failed to find object";
I'm back to exactly the same thing. Calling db.list_collections(document{}) retrieves no results.

The bsoncxx library has two document types, views and values. A document::value contains the actual document data, and a document::view is just a reference to some underlying value. Values must outlive the views that use them.
There's a bug in the new c++11 driver with how document::values are passed around. This code produces a document::value :
document{} << "someField" << "someValue" << finalize;
The collection.find_one() method takes a document::view, and document::values convert implicitly to document::views. Unfortunately, this means if you dynamically build a document in your call to find_one(), as above, you can shoot yourself in the foot:
collection.find_one(document{} << "someField" << "someValue" << finalize);
finalize makes a temporary document::value, then find_one converts that to a document::view. The temporary value is dropped on the floor, leaving your view value-less, like a dangling pointer.
A workaround is to make your value in a separate call, and keep it around:
document::value doc = document{} << "someField" << "someValue" << finalize;
collection.find_one(doc.view());
I suspect this is what's causing your queries to fail; if not, it's something to make your code resilient to nonetheless!
You can track this ticket for the real fix for this problem.

Related

Running arbitrary SQL commands MySQL C++ (X DevAPI)?

I've connected my C++ project to MySQL and successfully created a session. I was able to create a Schema. My issue is that when I try to run simple arbitrary queries like USE testSchema SHOW tables; using the MySQL/C++ api, I run into SQL syntax errors. When I run the function directly in the MySQL shell, the query runs perfectly fine.
Here is the full code
const char* url = (argc > 1 ? argv[1] : "mysqlx://pct#127.0.0.1");
cout << "Creating session on " << url << " ..." << endl;
Session sess(url);
{
cout << "Connected!" << endl;
// Create the Schema "testSchema"; This code creates a schema without issue
cout << "Creating Schema..." << endl;
sess.dropSchema("testSchema");
Schema mySchema = sess.createSchema("testSchema");
cout << "Schema Created!" << endl;
// Create the Table "testTable"; This code runs like normal, but the schema doesn't show
cout << "Creating Table with..." << endl;
SqlStatement sqlcomm = sess.sql("USE testSchema SHOW tables;");
sqlcomm.execute();
}
Here is the console output:
Creating session on mysqlx://pct#127.0.0.1 ...
Connected!
Creating Schema...
Schema Created!
Creating Table with...
MYSQL ERROR: CDK Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SHOW tables' at line 1
The error You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SHOW tables' at line 1 is a MySQL error that means I have a syntax error in the query, but when I take a closer look at a query, I see there is nothing wrong with it.
I've copied and pasted the code directly from the cpp file into the mysql shell and it runs perfectly. This tells me that something is up with the formatting of how I'm entering the query in the sql() function. But the documentation for the sql() function is really terse and.
Here is the reference to the sql() function: https://dev.mysql.com/doc/dev/connector-cpp/8.0/class_session.html#a2e625b5223acd2a3cbc5c02d653a1426
Can someone please give me some insight on where I'm going wrong? Also here here is the full cpp code for more context:https://pastebin.com/3kQY8THC
Windows 10
Visual Studio 2019
MySQL 8.0 with Connect/C++ X DevAPI
You can do it in two steps:
sess.sql("USE testSchema").execute();
SqlStatement sqlcomm = sess.sql("SHOW tables");
SqlResult res = sqlcomm.execute();
for(auto row : res)
{
std::cout << row.get(0).get<std::string>() << std::endl;
}
Also, you can use the Schema::getTables():
for(auto table : mySchema.getTables())
{
std::cout << table.getName() << std::endl;
}
Keep in mind that the Schema::getTables() doesn't show the Collections created by Schema::createCollection(). There is also a Schema::getCollections():
for(auto collection : mySchema.getCollections())
{
std::cout << collection.getName() << std::endl;
}

V8 Cannot set ObjectTemplate with name "console"

I try to set a global object named console, but that specific name causes a crash and to me it seems like it's telling me that the object already exists. I can though set it to anything else. Why can I not set the object to name "console"?
V8 Version is 6.5.254.6
Error
# Fatal error in ../../src/objects.cc, line 6007
# Debug check failed: !it.IsFound().
Code Snippet
isolate->Enter();
v8::HandleScope handle_scope(isolate);
// Create globals
auto globalObj = v8::ObjectTemplate::New(isolate);
// Create console object
auto consoleObj = v8::ObjectTemplate::New(isolate);
// Log
auto logcb = [](V8CallbackArgs args) {
auto& log = Log::Instance();
for (size_t i = 1; i < args.Length(); i++)
log << *v8::String::Utf8Value(args[i]);
log << std::endl;
};
consoleObj->Set(v8::String::NewFromUtf8(isolate, "log"), v8::FunctionTemplate::New(isolate, logcb));
// Set global object
globalObj->Set(v8::String::NewFromUtf8(isolate, "console"), consoleObj); // nonono cannot have it console, con is ok though
// Create script context
context = v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>>(isolate, v8::Context::New(isolate, nullptr, globalObj));
{
v8::Context::Scope context_scope(context.Get(isolate));
v8::TryCatch tc(isolate);
auto source = v8::String::NewFromUtf8(src.c_str());
auto script = v8::Script::Compile(source);
if (script->Run().IsEmpty() && CV8ScriptRuntime::isDebug) {
v8loge "Error loading script \"" << filepath << "\n" << std::endl
<< "Exception: " << *v8::String::Utf8Value(tc.Exception()) << std::endl
<< "Stack trace: " << *v8::String::Utf8Value(tc.StackTrace()) << std::endl << Log::White;
}
}
Your observation is correct. When V8 initializes a Context, it installs a global console object into it, and assumes (guarded by a check) that a property with that name does not exist yet. When you provide your own "console", that check fails.
If you want to overwrite V8's built-in console, you'll have to create the Context first (via v8::Context::New), then delete (or overwrite) the console property on its global object.
If all you wanted was to have a console object in your embedder just like the one you know from browsers, then I'm happy to inform you that this work has already been done and you can simply use it :-)

Error:"Parameter count mismatch" in QSQLite [duplicate]

I am using quite a lot of parameterized queries in my code for performance reasons. In short, some of them work, some don't.
I initialize the query during construction of my database wrapper like this:
QString querystring = QString("SELECT somevalue FROM sometable "
"WHERE one_feature = :one_feature AND other_feature = :other_feature ");
myquery = QSqlQuery(db);
myquery.setForwardOnly(true);
myquery.prepare(querystring);
myquery is a QSqlQuery member variable of my database wrapper. Later on, in the function that wants to use this query, I do something like
int db_wrapper::fetch_some_value (int arg1, int arg2) {
myquery.clear();
myquery.bindValue(":one_feature", arg1);
myquery.bindValue(":other_feature", arg2);
qDebug() << "Bound values: " << myquery.boundValues();
bool OK = myquery.exec();
if (!OK) {
int number = myquery.lastError().number();
qDebug() << "db error " << number;
qDebug() << "db error " << myquery.lastError().text();
#ifdef USE_EXCEPTIONS
throw "Could not fetch some_value!";
#endif
}
// process data...
}
I always get the same error message/output:
Bound values: QMap((":one_feature", QVariant(int, 1) ) ( ":other_feature" , QVariant(int, 1) ) )
db error -1
db error " Parameter count mismatch"
terminate called after throwing an instance of 'char const*'
The exception is not surprising, but the parameter count mismatch is. The call to boundValues actually shows the right values and all, still I get this error message. I have similar queries that work just fine.
I tried substituting positional bind values, renamed the placeholders, used ? and positional bind values, all to no avail. Does anyone have an idea what the problem might be?
I use Qt 4.7.3 and SQLite 3.7.4-2
Usually this error means that the SELECT/UPDATE query itself is incorrect. You did not give the schema of the database so it's not possible to pinpoint which one. So one or more of somevalue, sometable, one_feature, or second_feature is not in the database/table.

MySQL call procedure with output parameter from C++ mysqlpp

I need help with the C++ mysqlpp driver calling a stored procedure and retrieving its output parameter. The queries seem to pass successfully but trying to get the stored value causes segmentation fault. My current pseudo code is:
mysqlpp::Connection* connection; // the connection type I am bound to use, no createStatement, prepareStatement methods
Query query = connection->query();
Query transactionQuery = connection->query();
query << "CALL sp_get_transactions_count(" << inputId << ", #transactionsCount);";
transactionQuery << "SELECT #transactionsCount as combinations;";
ClearQuerySentry cleanUpQuery(transactionQuery);
query.exec();
mysqlpp::StoreQueryResult transactionsResult = transactionQuery.store();
if (!transactionsResult || transactionsResult.num_rows() == 0)
{
logWarning(....);
}
else
{
const mysqlpp::Row& transactionRecord = result[0];
environment.pairTransactionsCount = verboseLexicalCast<int>(transactionRecord, "combinations"); // segfault on trying to cast static_cast<const char*>(row[fieldName.c_str()]))
}
I am not very experienced with mysqlpp and MySQL as a whole so it is possible my perception of the solution to be wrong. Thanks in advance.

Connection to Postgres Database using libpqxx

I am using libpqxx to connect to a postgres database by creating a class.
class databaseConnection
{
public:
pqxx::connection* conn;
void SetConnection(){
conn=new pqxx::connection(
"username=temp "
"host=db.corral.tacc.utexas.edu "
"password=timelione "
"dbname=temp");
}
void Disconnect(){
conn->disconnect();
}
pqxx::result query(std::string strSQL){
//SetConnection();
pqxx::work trans(*conn,"trans");
pqxx::result res=trans.exec(strSQL);
trans.commit();
return res;
}
};
int main()
{
databaseConnection* pdatabase;
pdatabase->SetConnection();
return 0;
}
I am getting error that says
terminate called after throwing an instance of 'pqxx::broken_connection'
what(): invalid connection option "database"
Can anyone help me out?
Thanks
pgxx::connection(const PGSTD::string&) is basically a wrapper around libpq's PQconnectdb() function, so the supported connection parameter keywords are the same as for libpq.
The parameter key word for the PostgreSQL user name to connect as is user, not username. Perhaps correcting that will fix the problem.
Also, in your sample code, pdatabase is an uninitialized pointer. You could either allocate a databaseConnection object on the stack with:
databaseConnection database;
database.SetConnection();
or use new to heap-allocate a databaseConnection object:
databaseConnection* pdatabase = new databaseConnection();
pdatabase->SetConnection();
But you need to pick one.
if you try like this
try
{
conn = new pqxx::connection(
"username=temp "
"host=db.corral.tacc.utexas.edu "
"password=timelione "
"dbname=temp");
}
catch (const std::exception &e)
{
std::cerr << e.what() << std::endl;
}
it catches the exception about connection string:
invalid connection option "username"
You might also need to add port=5432 to your connection string.