Iterate over results in neo4j_client for C++ - c++

I am looking for examples on usage for neo4j_client in C++. In the test suite I see the neo4j_result_t, but no example of iterating or calling fields by name. Is that possible?

Results are returned as a neo4j_result_stream_t, which represents a stream of result rows. The number of the columns in the result is available via neo4j_nfields, and their names via neo4j_fieldname, both of which take the neo4j_result_stream_t pointer as a parameter.
To iterate over the result rows, use neo4j_fetch_next which returns a neo4j_result_t. And to extract values for each column from the row (the fields), pass the pointer to neo4j_result_field (along with the index of the column).
An example would be something like this:
neo4j_result_stream_t *results =
neo4j_run(session, "MATCH (n) RETURN n.name, n.age", neo4j_null);
if (results == NULL)
{
neo4j_perror(stderr, errno, "Failed to run statement");
return EXIT_FAILURE;
}
int ncolumns = neo4j_nfields(results);
if (ncolumns < 0)
{
neo4j_perror(stderr, errno, "Failed to retrieve results");
return EXIT_FAILURE;
}
neo4j_result_t *result;
while ((result = neo4j_fetch_next(results)) != NULL)
{
unsigned int i;
for (i = 0; i < ncolumns; ++i)
{
if (i > 0)
{
printf(", ");
}
neo4j_value_t value = neo4j_result_field(result, i);
neo4j_fprint(value, stdout);
}
printf("\n");
}

Related

How to retrieve table values row by row instead of column by column

So I have a table called users which looks like this:
id
name
age
1
sid
25
2
jack
40
And I'm trying to get the values in order by row:
1
sid
25
2
jack
40
But I end up with this result instead:
1
2
sid
jack
25
40
Here is a snippet my code:
std::vector<std::string> Sqlite3::get_rows(const std::string& command) {
if(!handle) throw std::runtime_error("database is not connected");
sqlite3_stmt * stmt = nullptr;
std::vector<std::string> values = {};
// Prepare (compile) statement
if(sqlite3_prepare_v2(handle, command.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
neroshop::print("sqlite3_prepare_v2: " + std::string(sqlite3_errmsg(handle)), 1);
return {};
}
// Check whether the prepared statement returns no data (for example an UPDATE)
if(sqlite3_column_count(stmt) == 0) {
neroshop::print("No data found. Be sure to use an appropriate SELECT statement", 1);
return {};
}
int result = 0;
for(int i = 0; i < sqlite3_column_count(stmt); i++) {
while((result = sqlite3_step(stmt)) == SQLITE_ROW) {
std::cout << sqlite3_column_text(stmt, i) << std::endl;
values.push_back(reinterpret_cast<const char *>(sqlite3_column_text(stmt, i)));
}
}
if(result != SQLITE_DONE) {
neroshop::print("sqlite3_step: " + std::string(sqlite3_errmsg(handle)), 1);
}
sqlite3_finalize(stmt);
return values;
}
I've used PostgreSQL before and it has a function for retrieving table values row by row (PQgetvalue(result, row_index, column_index)). Does sqlite have something similar or am I just doing something wrong here?

Char* data changes when accessed

I am working on a c++ application that has a function
//ControllerCore.cpp
Report ControllerCore::GetReport() {
unsigned char buf[256];
int res = 0;
while (res == 0) {
res = get_unsigned_char*(buf, sizeof(buf));
if (res < 0)
printf("Unable to read()\n");
#ifdef WIN32
Sleep(50);
#else
usleep(50 * 1000);
#endif
}
Report report = Report();
report.data = buf;
report.dataLength = res;
return report;
}
Report is defined as
//Report.h
struct Report
{
public:
unsigned char* data;
int dataLength;
};
When ContollerCore::GetReport() returns it assigns report.data to the pointer to an array of unsigned characters that I can work with fine. But when the caller tries to print report.data the values of the array change.
//Main.cpp
int RequestReport() {
Report report = core.GetReport();
for (int i = 0; i < report.dataLength; i++) {
std::cout << "0x" << std::hex << (int)report.data[i] << ", ";
}
std::cout << std::endl;
return 1;
}
You're returning a pointer to a local array. As soon as ControlerCore::GetReport returns, buf goes out of scope and is destroyed. Any attempt to access it after that leads to undefined behavior.
You need make Report actually hold the data directly. The easiest way would be to use a std::vector:
struct Report
{
std::vector<unsigned char> data;
// don't need dataLength anymore since std::vector knows its size
};
Report ControllerCore::GetReport() {
Report report;
report.data.resize(256);
int res = 0;
while (res == 0) {
res = get_data(report.data.data(), report.data.size());
}
report.data.resize(res);
return report;
}
Now that Report has only one member it probably isn't needed anymore, and you could just return std::vector<unsigned char> directly instead.
If you want to avoid the dynamic allocation used by std::vector, you could use std::array (or a raw array) instead:
struct Report
{
std::array<unsigned char, 256> data;
size_t dataLength; // back now, since the length of the data won't match the size of the contianer
};
Report ControllerCore::GetReport() {
Report report;
int res = 0;
while (res == 0) {
res = get_data(report.data.data(), report.data.size());
}
report.dataLength = res;
return report;
}
This avoids the dynamic allocation, but does incur an extra copy of the data since std::array can't be efficiently moved like std::vector can. That means that unless dynamic allocation is especially slow on your platform, the std::vector version is probably going to be faster.
You can try using report.data itself instead of buf.
Report ControllerCore::GetReport() {
Report report;
report.data=new char[256];
int res = 0;
while (res == 0) {
res = get_unsigned_char*(report.data, sizeof(char)*256);
if (res < 0)
printf("Unable to read()\n");
#ifdef WIN32
Sleep(50);
#else
usleep(50 * 1000);
#endif
}
report.dataLength = res;
return report;
}

Arrays giving me errors:: String subscript out of range; but everything seems to be in order

I've run into some problems with arrays, one while I was coding in Winsock and one in DirectX 11. In DirectX 11 its actually a texture array that I'm trying to release.
Here's the Winsock problem:
int retval;
retval = recv(hclientSocket, tempBuffer, sizeof(tempBuffer), 0);
if (retval == 0)
{
break; // Connection has been closed
}
else if (retval == SOCKET_ERROR)
{
throw ErrorHandler("Failed to receive due to socket");
}
else
{
Encyrption enc;
string done = enc.Cipher(tempBuffer, retval);
retval = retval * 3;
cout << retval; // it prints out 3
for (int i = 0; i < retval; i++) {
tempBuffer[i] = done[i]; //the error is being pointed here on the 6th time it runs through this, even though its only suppose to go through this 3 times
}
if (send(hclientSocket, tempBuffer, retval, 0) == SOCKET_ERROR)
throw ErrorHandler("Failed to send due to socket");
}
okay most of this code I got from a Winsock tutorial place, but I wanted to try a different encryption method.
Here's the call function, because originally intended to pass and return a string but this time I'm passing a char* and returning a string, which is converted in the above code.
The encryption takes in one character and turns it into a string of 3 for example a would become bca and c would become cba or something that's why I'm multiplying retval by 3. It prints out everything I want it to print out, but its giving an error after its done.
string pass = (string)message;
pass.resize(size);
for (int i = 0; i < size; i++) {
if (!isalnum(pass[i])) {
return "\n";
}
else {
return Cipher(pass);
}
}
Okay so here's the Directx11 problem
I recently learned how to use multitextures utilizing a texture array, and Im having trouble releasing it.
#define TEXTURE_ELEMENTS_COUNT 2
ID3D11ShaderResourceView* m_textures[TEXTURE_ELEMENTS_COUNT];
for (int i = 0; i <= TEXTURE_ELEMENTS_COUNT; i++) {
m_textures[i] = 0;
}
//some code here
for (int i = 1; i <= (TEXTURE_ELEMENTS_COUNT - 1); i++) {
m_textures[i]->Release(); //it throws an exception right here, but I can't figure out why, I tried change `i` to zero, but it still throws it.
m_textures[i] = 0;
}
Thanks for taking the time to look through my code, I have no idea what I'm doing wrong and arrays sometimes throw me off, because its suppose to start at zero and sometimes its hard for me to visualize. Anyway thanks for any input in advance.
Your element count is 2. Therefore you have an element at position 0 and at position 1.
So you have to start your loop at "i = 0" and end your loop after "i = 1". So start from 0 and run to "i < maxCount".
for (int i = 0; i < TEXTURE_ELEMENTS_COUNT; i++) { //FROM 0 TO i<MAXCOUNT
m_textures[i] = 0; // HERE YOU CREATE A NULLPTR TO EVERY SRV
}
//some code here
for (int i = 0; i < (TEXTURE_ELEMENTS_COUNT); i++) { //USE THE SAME LOOP
m_textures[i]->Release(); //IF THERE IS ALREADY A NULLPTR YOU HAVE AN INVALID ACCESS
m_textures[i] = 0;
}
Try to use the Safe_Release function if you use the SDK. Otherwise define it for yourself.
SAFE_RELEASE(m_textures[i])
There is an included test for nullptr:
#ifndef SAFE_RELEASE
#define SAFE_RELEASE(x)
if(x != NULL)
{
x->Release();
x = NULL;
}
#endif
Good Luck

Error: not all control paths return a value

I am writing two functions in a program to check if a string has an assigned numeric code to its structure array or if the given numeric code has an assigned string in the same structure array. Basically, if I only know one of the two, I can get the other. I wrote the following:
int PrimaryIndex::check_title_pos(std::string title) {
bool findPos = true;
if (findPos) {
for (int s = 1; s <= 25; s++) {
if (my_list[s].title == title) {
return s;
}
}
} else {
return -1;
}
}
std::string PrimaryIndex::check_title_at_pos(int pos) {
bool findTitle = true;
if (findTitle) {
for (int p = 1; p <= 25; p++) {
if (my_list[p].tag == pos) {
return my_list[p].title;
}
}
} else {
return "No title retrievable from " + pos;
}
}
However, it says not all control paths have a return value. I thought the else {} statement would handle that but it's not. Likewise, I added default "return -1;" and "return "";" to the appropriate functions handling int and string, respectively. That just caused it to error out.
Any idea on how I can keep this code, as I'd like to think it works but cant test it, while giving my compiler happiness? I realize through other searches that it sees conditions that could otherwise end in no returning values but theoretically, if I am right, it should work fine. :|
Thanks
In the below snippet, if s iterates to 26 without the inner if ever evaluating to true then a return statement is never reached.
if (findPos) {
for (int s = 1; s <= 25; s++) {
if (my_list[s].title == title) {
return s;
}
}
}

COM: pass reference to a SAFEARRAY

Introduction
I want to query a COM function with Qt. I have a documentation but for VB. Nevertheless this doc says:
Object.Frequencies DataArray
Object -> An object expression that evaluates to a BKDataSet object.
DataArray -> An array of strings or an array of values
The DataArray structure must be declared in the application that is controlling PULSE and the size of the array must be equal to the number of x-axis entries. In Visual Basic, use the DIM (or corresponding) statement to declare the variable and allocate storage space. In other languages use a safearray of strings (VT_BSTR) or reals (VT_R8 for double or VT_R4 for float/single).
Step 1
First I used OLEVIEW to see what the function prototype really looks like.
I got: void Frequencies(VARIANT* FrequencyArray).
So I tried to do it with Qt:
IBKDataSet *data = function->FunctionData();
int nbFrequencies = data->dynamicCall("GetNumberOfXAxisEntries()").toInt();
QList<QVariant> frequencies;
for(int i=0; i<nbFrequencies; j++) {
frequencies << 0.0;
}
QList<QVariant> parameters;
parameters << QVariant(frequencies);
data->dynamicCall("Frequencies(QVariant&)", parameters);
for(int i=0; i<frequencies.size(); i++) {
qDebug() << frequencies.at(i);
}
Note: I used a QList<QVariant> as it is shown here.
But I had the following message Type Mismatch in Parameter. Pass an array of type string or real..
Step 2
So I tried with an array of string:
IBKDataSet *data = function->FunctionData();
int nbFrequencies = data->dynamicCall("GetNumberOfXAxisEntries()").toInt();
QList<QString> frequencies;
for(int i=0; i<nbFrequencies; i++) {
frequencies << "0.0";
}
QList<QVariant> parameters;
parameters << QVariant(frequencies);
data->dynamicCall("Frequencies(QList<QString>&)", parameters);
for(int j=0; j<frequencies.size(); j++) {
qDebug() << frequencies.at(j);
}
No more error but the returned values are the values set during the initialization (I tried with several ones, not only 0.0).
Step 3
After that, I tried many combinations with no success. So I asked the developers (hard to contact) to provide an example. They sent me the following code (Visual-C++):
IBKDataSetPtr bkDataSet(function->FunctionData);
int nEntries = bkDataSet->GetNumberOfXAxisEntries();
COleSafeArray safeArray;
safeArray.CreateOneDim( VT_R8, nEntries);
COleVariant vDontCare;
bkDataSet->Frequencies(&safeArray);
double* pFrequencyData;
safeArray.AccessData((void**)&pFrequencyData);
CString sMessage;
sMessage.Format("Y[1] = %1.4e ", pFrequencyData[1]);
MessageBox(sMessage);
safeArray.UnaccessData();
Question
How this code can be used in QtCreator?
I realized COleSafeArray is specific to VisualStudio...
I am sorry for the length of the post but this is a while I'm trying to get around this issue without success.
EDIT
Here is a clue on how to do that with the WIN32 API:
QList<double> getCOMValues(IDispatch *dispatch, const QString &method, int arraySize) const {
QList<double> result;
HRESULT hr;
// I don't know how to convert a QString into an OLECHAR*
OLECHAR * szMember = L"Frequencies";
DISPID dispid;
// Retrieve the dispatch identifier for the method.
// Use defaults where possible.
hr = dispatch->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_USER_DEFAULT, &dispid);
// Test return is OK
if(FAILED(hr)) {
qDebug() << "Error while trying to read the " << method;
return result;
}
// Defines a SAFEARRAY.
SAFEARRAY *psa;
// Represents the bounds of one dimension of the array.
SAFEARRAYBOUND freqBound[1];
// The lower bound of the dimension starts at 0.
freqBound[0].lLbound = 0;
// The number of elements in the dimension is the number of frequencies.
freqBound[0].cElements = arraySize;
// Creates a new array descriptor, allocates and initializes the data for
// the array, and returns a pointer to the new array descriptor.
// VT_R8 represents double.
// 1 is the number of dimensions in the array.
psa = SafeArrayCreate(VT_R8, 1, freqBound);
// Check the array is not NULL.
if(psa == NULL) {
qDebug() << "Error while trying to read the " << method;
return result;
}
// This is the default value to put into the array.
double init[] = {0.0};
// Populates the array with 0.0.
for(long index=0;index<arraySize;index++)
{
// Stores the data element at the specified location in the array.
hr = SafeArrayPutElement(psa,&index,init);
if( FAILED(hr)) {
qDebug() << "Error while initialising the array for " << method;
}
}
// Describes arguments passed within DISPPARAMS.
VARIANTARG v[1];
// A safe array descriptor, which describes the dimensions, size, and in-memory location of the array.
v[0].parray = psa;
// The type of data in the union.
v[0].vt = VT_ARRAY|VT_R8;
// Contains the arguments passed to a method or property.
DISPPARAMS params = {v, NULL, 1, 0};
// To catch errors
EXCEPINFO pExcepInfo;
// Provides access to properties and methods exposed by the object.
hr = dispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, &pExcepInfo, NULL);
if(FAILED(hr)) {
if(hr == DISP_E_EXCEPTION) {
printf("%S\n", pExcepInfo.bstrSource);
printf("%S\n", pExcepInfo.bstrDescription);
}
qDebug() << "Error while trying to read the " << method;
return result;
}
double res = 0;
for(long idx=0; idx<arraySize; idx++) {
hr = SafeArrayGetElement(psa, &idx, &res);
if(hr == S_OK) {
result.push_back(res);
} else {
result.push_back(0.0);
qDebug() << "Error while trying to read the " << method;
}
}
// Clears the variant.
hr = VariantClear(v);
return result;
}
But the Invoke method returns a DISP_E_EXCEPTION: Type Mismatch in Parameter. Pass an array of type string or real.
Found the problem. Very simple!
IBKDataSet *data = function->FunctionData();
int nbFrequencies = data->dynamicCall("GetNumberOfXAxisEntries()").toInt();
QList<QString> frequencies;
for(int i=0; i<nbFrequencies; i++) {
frequencies << "0.0";
}
QList<QVariant> parameters;
parameters << QVariant(frequencies);
data->dynamicCall("Frequencies(QList<QString>&)", parameters);
frequencies = parameters.first().toStringList();
for(int j=0; j<frequencies.size(); j++) {
qDebug() << frequencies.at(j);
}
I had to read the first element of parameters and convert it to a QStringList...