Add multiple parameters to IN clause in SQLAPI c++ - c++

I am using SQLAPI to connect to a SQL-Server database from a C++ code. I need to execute a simple select statement with a IN clause, where the string values in the clause is received as a vector of strings. We want to use parameterised queries so did something like this:
std::string getSQLQuery(std::vector<std::string> ids){
std::stringstream sql;
sql << "SELECT ID, Name, DOB FROM Employees WHERE ID IN (";
unsigned int counter = 0;
for each (auto id in ids)
{
sql << ":" << counter + 1;
if (++counter < ids.size())
{
sql << ",";
}
}
sql << ")";
return sql.str();
}
And then,
int param_counter = 0;
for each (auto id in ids) {
command.Param(++param_counter).setAsString() = id.c_str();
}
Can anyone please suggest a better way of doing it?

Well, I don't want to undercut your basic question, which I take to be "What's a good way to do this?", but you have some basic syntax problems with your C++. Inferring your intention from the buggy code above, I gather that the goal is to create a command synthesizer with a common SQL select query from an arbitrary set of input id's. Cool. I don't think there's any up-side to first creating a synthesized template command with insertion points and then using their parameter replacement scheme. Might as well do the synthesis all at once. A compile-time-correct version would look something like this (with a few tweaks to make it more reusable) -
std::string getSQLQuery(
const std::string& columns
, const std::string& table
, const std::vector<std::string>& ids
){
// Check for empty strings/arrays here - leads to illegal SQL,
// so error out or except on empty ids, columns, or "table".
std::stringstream sql("SELECT ", std::ios_base::out | std::ios_base::ate);
sql << columns << " FROM " << table << " WHERE ID IN ( ";
// Trailing commas are not allowed in SQL, which makes synthesis a little trickier.
// We checked for empty inputs earlier, so we have at least one ID.
auto iter = ids.begin();
sql << *iter++; // add the first (and possibly only) ID
for (; iter != ids.end(); ++iter) { // add the rest (if any) with commas
sql << ", " << *iter;
}
sql << " )"; // <- should this be " );"? Or does SQLAPI++ deal with that?
return sql.str(); // There's a shrink-to-fit method you may want to use here.
}
Now you can just do something like -
std::vector<std::string> id_array{ "1", "50", "aardvark" };
SACommand basic_command(connection, getSQLQuery("ID, Name, DOB", "Employees", id_array));
basic_command.Execute();
This skips the second substitution phase entirely. The SQLAPI++ parameter substitution is intended for queries with a much more rigid template, but you're doing something more dynamic. You can imagine extending this further with input arrays of columns as well, to avoid syntax errors in the table list (like we do in the id list). Also, since id's are often numerical, you could make the id array std::vector<std::uint64_t> or whatever fits your specific application. In fact, you can handle both cases with the same body of code by making the signature -
template<typename T> std::string getSQLQuery(
const std::string& columns
, const std::string& table
, const std::vector<T>& ids
){
... // rest of the implementation is the same
}
I'm a new contributor, but a long-time user, so just a word about questions. When you ask a question like, "Can anyone please suggest a better way of doing it?", the answer is always "Yes.". There are a lot of smart people out there and an infinity of solutions to every high-level problem. In the future, you want to state the problem you're trying to solve (not hard to figure out in this case), and if you show a solution that was tried and failed, you should give specifics about how it failed. In the case of the code you put forth, the most obvious reason it failed is that it is syntactically wrong - the compiler would not accept it. "for each" is from some other languages. In C++, it's something like "for (auto id : ids)". But if you were just trying to show some kind of pseudo-code, it suggests that you don't really know if your existing approach works, because it hasn't been tried. And even in that case, you should say what you don't like about the presented solution (like the unnecessary second step of using the SQLAPI++ substitution scheme), and ask specifically if someone can think of a way to remove that. I'm a talker, and I would have given the same response, but for future reference, try to avoid a question that comes down to, "The following code is broken. Someone fix it for me." Just FWIW.

Related

Best approach to query a database to create a collection of a custom class in C++

I am new to interfaces with databases through c++ and was wondering what is the best approach to do the following:
I have an object with member variables that I define ahead of time, and member variables that I need to pull from a database given the known variables. For example:
class DataObject
{
public:
int input1;
string input2;
double output1;
DataObject(int Input1, string Input2) :
input1(Input1), input2(Input2)
{
output1 = Initializer(input1,input2);
}
private:
Initializer(int, string);
static RecordSet rs; //I am just guessing the object would be called RecordSet
}
Now, I can do something like:
std::vector<DataObject> v;
for (int n = 0; n <= 10; ++n)
for (char w = 'a'; w <= 'z'; ++w)
v.push_back(DataObject{n,z});
And get an initialized vector of DataObjects. Behind the scenes, Initializer will check check if rs already has data. If not, it will connect to the database and query something like: select input1, input2, output1 from ... where input1 between 1 and 10 and input 2 between 'a' and 'z', and then start initializing each DataObject with output1 given each pair of input1 and input2.
This would be utterly simple in C#, but from code samples I have found online it looks utterly ugly in C++. I am stuck on two things. As stated earlier, I am completely new to database interfaces in C++, and there are so many methods from which to choose, but I would like to hone in on a specific method that truly fits my purpose. Furthermore - and this is the purpose - I am trying to make use of a static data set to pull data in a single query, rather than run a new query for each input1/input2 combination; even better yet, is there a way to have database results written directly into the newly created DataObjects rather than making a pit stop in some temporary RecordSet object.
To summarize and clarify: I have database on a relational database, and I am trying to pull the data and store it into a collection of objects. How do I do this? Any tips/direction - I am much obliged.
EDIT 8/16/17: After some research and trials I have come up with the below
So I've had progress by using an ADORecordset with the put_CursorLocation set to adUseServer:
rs->put_CursorLocation(adUseServer)
My understanding is that by using this setting the query result is stored on the server, and the client side only gets the current row pointed to by rs.
So I get my data from the row and create the DataObject on the spot, emplace_back it into the vector, and finally call rs->MoveNext() to get the next row and repeat until I reach the end. Partial example as follows:
std::vector<DataObject> v;
DataObject::rs.Open(connString,Sql); // Connection for wrapper class
for (int n = 0; n <= 10; ++n)
for (char w = 'a'; w <= 'z'; ++w)
v.emplace_back(DataObject{n,z});
// Somewhere else...
void DataObject::Initializer(int a, string b) {
int ra; string rb; double rc;
// For simplicity's sake, let's assume the result set is ordered
// in the same way as the for-loop, and that no data is missing.
// So the below sanity-check would be unnecessary, but included.
while (!rs.IsEOF())
{
// Let's assume I defined these 'Get' functions
ra = rs.Get<int>("Input1");
rb = rs.Get<string>("Input2");
rc = rs.Get<double>("Output1");
rs.MoveNext();
if (ra == a && rb == b) break;
}
return rc;
}
// Constructor for RecordSet:
RecordSet::RecordSet()
{
HRESULT hr = rs_.CoCreateInstance(CLSID_CADORecordset);
ATLENSURE_SUCCEEDED(hr);
rs_->put_CursorLocation(adUseServer);
}
Now I'm hoping that I interpreted how this works correctly; otherwise, this would be a whole lot of fuss over nothing. I am not an ADO or .Net expert - clearly - but I'm hoping someone can chime in to confirm that this is indeed how this works, and perhaps shed some more light on the topic. On my end, I tested the memory usage using VS2015's diagnostic tool, and the heap seems to be significantly larger when using adUseClient. If my conjecture is correct, then why would anyone opt to use adUseClient, or any of the other choices, over adUseServer.
I think of two options: by member type and BLOB.
For classes, I recommend one row per class instance with one column per member. Search the supported data types by your database. There are some common types.
Another method is to use the BLOB (Binary Large OBject) data type. This is a "binary" data type used for storing data-as-is.
You can use the BLOB type for members that are of unsupported data types.
You can get more complicated by researching "Database Normalization" or "Database normal forms".

C++ Standard Library hash code sample

I solved a problem to find duplicates in a list
I used the property of a set that it contains only unique members
set<int> s;
// insert the new item into the set
s.insert(nums[index]);
// if size does not increase there is a duplicate
if (s.size() == previousSize)
{
DuplicateFlag = true;
break;
}
Now I am trying to solve the same problem with hash functions in the Standard Library. I have sample code like this
#include <functional>
using namespace __gnu_cxx;
using namespace std;
hash<int> hash_fn2;
int x = 34567672;
size_t int_hash2 = hash_fn2(x);
cout << x << " " << int_hash2 << '\n';
x and int_hash2 are always the same
Am I missing something here ?
For std::hash<int>, it's ok to directly return the original int value. From the specification, it only needs to ensure that for two different parameters k1 and k2 that are not equal, the probability that std::hash<Key>()(k1) == std::hash<Key>()(k2) should be very small, approaching 1.0/std::numeric_limits<size_t>::max(). Clearly returning the original value satisfies the requirement for std::hash<int>.
x and int_hash2 are always the same Am I missing something here ?
Yes. You say "I am trying to solve the same problem with hash functions", but hash functions are not functional alternatives to std::set<>s, and can not - by themselves - be used to solve your poroblem. You probably want to use a std::unordered_set<>, which will internally use a hash table, using the std::hash<> function (by default) to help it map from elements to "buckets". For the purposes of a hash table, a hash function for integers that returns the input is usually good enough, and if it's not the programmer's expected to provide their preferred alternative as a template parameter.
Anyway, all you have to do to try a hash table approach is change std:set<int> s; to std::unordered_set<int> s; in your original code.

How to find the length of an array of std::strings?

I have a few questions related to portions of my code.
The first has to do with how I find the length of an array of arrays of strings. I'm using the following as a map for a Calculus tool I'm using.
std::string dMap[][10] = {{"x", "1"}, {"log(x)", "1/x"}, {"e^x", "e^x"}};
I'm wondering how to do the equivalent of
int arr[] = {1, 69, 2};
int arrlen = sizeof(arr)/sizeof(int);
with an array of elements of type std::string. Also, is there a better way of storing symbolic representations of (f(x), f'(x)) pairs? I'm trying to not use C++11.
My next question has to do with a procedure I wrote that isn't working. Here it is:
std::string CalculusWizard::composeFunction(const std::string & fx, const char & x, const std::string & gx)
{
/* Return fx compose gx, i.e. return a string that is gx with every instance of the character x replaced
by the equation gx.
E.g. fx="x^2", x="x", gx="sin(x)" ---> composeFunction(fx, x, gx) = "(sin(x))^2"
*/
std::string hx(""); // equation to return
std::string lastString("");
for (std::string::const_iterator it(fx.begin()), offend(fx.end()); it != offend; ++it)
{
if (*it == x)
{
hx += "(" + gx + ")";
lastString.erase(lastString.begin(), lastString.end());
}
else
{
lastString.push_back(*it);
}
}
return hx;
}
First of all, where's the bug in the procedure? It's not working when I test it out.
Second of all, when trying to make a string empty again, is it faster to do
lastString.erase(lastString.begin(), lastString.end());
or
lastString = "";
???
Thank you for your time.
Question 1) Understand that you can't, and really don't need to, calculate the size of a String this way. Just ask it how big it is and it will tell you.
// comparing size, length, capacity and max_size
#include <iostream>
#include <string>
int main ()
{
std::string str ("Test string");
std::cout << "size: " << str.size() << "\n";
std::cout << "length: " << str.length() << "\n";
std::cout << "capacity: " << str.capacity() << "\n";
std::cout << "max_size: " << str.max_size() << "\n";
return 0;
}
http://www.cplusplus.com/reference/string/string/capacity/
As for an array of strings, well go read this:
How to determine the size of an array of strings in C++?
Check out David Rodríguez's answer.
Question 2) The better way might be to define a FunctionPair class depending on what you're doing with them. Vector<FunctionPair> might come in handy.
If FunctionPair doesn't end up with any behavior (functions) associated with it then a struct might be enough: std::pair<std::string, std::string> could also be shoved into a vector.
You don't need a map unless your going to use one function string to look up the other.
http://www.cplusplus.com/reference/map/map/
Question 3) A little better description of what's not working would help. I notice lastString doesn't impact hx at all.
Question 4) "Second of all" Fastest is nothing to worry about at this point. Write what is easiest to look at until all the bugs are gone. "Premature optimization is the root of all evil", Donald Knuth.
Tip: Look into how the replace function might help you do the composition replacements:
http://www.cplusplus.com/reference/string/string/replace/
As the above commenter said, you shouldn't use c-style arrays even if you just want to make things 'easy'.
In reality doing things like that makes things harder.
c-style arrays aren't bounds checked. That means they are a source of bugs due to memory unsafety and can lead to all kinds of issues from segfaulting to corrupting data as you read random data from unrelated blocks of memory or even worse write to them.
#include <iostream>
int main() {
int nums[] = {1, 2, 3};
std::cout << nums[3] << std::endl;
}
.
# ./a.out
4196544
No programmer is perfect, every time you implement something like that there is a percentage chance you will be off by one in your bounds or something. Even if you are some programming god most people have to work on a team with people who aren't. In many cases no one will even notice since not every time will cause anything obvious. Memory can be randomly corrupted without causing anything to crash horribly. Until you make a totally unrelated change that causes the memory to be in a different order.
But when you do notice it will often effect something totally unrelated that you code sometime later. Given the fact that you will likely implement many such arrays in your programming lifetime you will likely make things much worse for yourself, you save yourself 10 minutes for each project but end up spending hours tracking down a bug in one.
If you really don't want C++11 then use std::vector<std::vector<std::string>>. It will use a little more memory so you might loose some performance , but most of the time when people are worried about performance they shouldn't be. Are you are calling this function 10,000 time a second? Even then you could gain more performance from threading the code or preallocating memory. Most of the time people think something has bad performance but in reality the computer is optimizing it away, or the CPU is. Is the performance from the memory allocation going to be worse than trying to find the array size every run?
This is also the case with raw pointers vs std::unique_ptr, std::shared_ptr.
If typing all those names looks like a pain, use a typedef to make it nice.
You can also look at using Boost's Array type, boost::array. Or whip up your own custom class.
That's not to say that you should never use that stuff. But you should only use it when you can justify it. The default should be the 'pure' C++ style code.
Performance (only when you have measured and see that you need it there).
C compatibility (but most of the time you can just wrap that stuff in the std classes anyway).
If you do feel you need it then. Make sure you unittest your code. And look at using the address and memory sanitizers that ship in current versions of gcc and clang. And quarantine the code as much as possible (ie in classe)s.
That all sounds like a lot of work, but once you have learned to do it, it becomes a habit and build it into your build system then it's just part of the development process. As easy as make test. And once you have it in one build system, you cut and paste it into everything else you do forever. You have expanded your programmers toolkit. That's all good habits to form even if you don't do that.
But here's the actual answer to your array size question:
std::string arr[][10] = {
{"xxx", "111"},
{"y", "222"},
{"hello", "goodbye"},
{"I like candy", "mmmm"},
{"Math goes here", "this is math"},
{"More random stuff", "adsfdsfasf"},
};
int size = sizeof(arr) / 10 / sizeof(std::string);
std::cout << size << endl; // Prints 6, as in 6 pairs of strings
Since the semantics is similar as Map ( you are mapping a function to it's differential), I guess most suitable data structure would be std::map, when you can easily get the differential using the function as index.
About the function, you are not appending lastString.
return hx+lastString;
Question 1 is actually quite straightforward:
std::string dMap[][10] = {{"x", "1"}, {"log(x)", "1/x"}, {"e^x", "e^x"}};
size_t tupleCount = sizeof(dMap)/sizeof(dMap[0]);
size_t maxTupleSize = sizeof(dMap[0])/sizeof(dMap[0][0]);
assert(tupleCount == 3);
assert(maxTupleSize == 10);
Note that you won't get the actual count of strings in a tuple this way. You only get the amount of std::strings that can fit into each tuple. Of course, you can search your tuples for the first default constructed std::string it contains. But the entire setup is an invitation for bugs, so you don't want to use it anyways (see below).
Question 2 can also be answered quite clearly. You should be using an std::unordered_map<>. Why?
You usecase is to map strings of one class to another. That is the semantics of either std::map<> or std::unordered_map<>.
From your question I gather that you don't need a notion of a next or previous mapping, your mapping pairs are essentially unrelated. In this case, std::unordered_map<> is simply faster than std::map<> because it uses a hash table internally. No matter how big your std::unordered_map<> gets, looking up its elements takes a constant amount of time. This is not true for std::map<>.

C++ Access member of struct/class using map

I need to search a database made up of a linked list of pointers to a struct called Person. Inside Person there is a bunch of data - first name, last name, social security, etc. It's all fictional and inconsequential. My problem is that I need to do a search based on user input, which determines what part of the struct is being compared for the search. Since all of the data is stored as members of the struct Person, I think the best way to do this (as in not writing 8 search functions) is by mapping, but my grasp of mapping is so poor as to be nearly non-existent. Here is the relevant code:
List * find(List * database, //mapping stuff, string name)
{
//run search
return database;
}
void search(List * database)
{
string field, searchtype, userinput;
cout << "To search for a person, enter information in this format: 'field equal
value' or 'field begins value'. Type 'clear' to
return to original database. Type 'exit' to leave the program\n";
while(field != "exit")
{
cin >> field >> searchtype >> userinput;
if(userinput == "firstname") //this is just for example, I would have to write one of these out for each parameter.
{
List * smallerdb = find(database, map(//mapping stuff?), string userinput);
}
}
}
This is for school, so please don't suggest I just use another library, as I can't. Thank you!
Each data-type will have to be compared differently, so without explicitly knowing the data-types you are out of luck. Strings are compared alphabetically, numbers are compared by value, and i'm not sure if you have any other custom data-types.
So you don't really have much of an option here besides going through each of the case-by-case scenarios. E.g.
if type == 'name' // compare each Person.name as string
else if type == 'socialSecurity' // compare Person.socialSecurity as int
else if ...
Here is a suggestion for making this code a bit more robust.
Instead of handling the search logic in each of the cases, you can simply return a function pointer than tells you how to compare two Persons. The actual function may be comparing by name, age, social security, or whatever, but your search function won't have to care about that once it has the function pointer that tells it how to compare two Person objects.

What is the best way to use two keys with a std::map?

I have a std::map that I'm using to store values for x and y coordinates. My data is very sparse, so I don't want to use arrays or vectors, which would result in a massive waste of memory. My data ranges from -250000 to 250000, but I'll only have a few thousand points at the most.
Currently I'm creating a std::string with the two coordinates (i.e. "12x45") and using it as a key. This doesn't seem like the best way to do it.
My other thoughts were to use an int64 and shove the two int32s into it and use it as a key.
Or to use a class with the two coordinates. What are the requirements on a class that is to be used as the key?
What is the best way to do this? I'd rather not use a map of maps.
Use std::pair<int32,int32> for the key:
std::map<std::pair<int,int>, int> myMap;
myMap[std::make_pair(10,20)] = 25;
std::cout << myMap[std::make_pair(10,20)] << std::endl;
I usually solve this kind of problem like this:
struct Point {
int x;
int y;
};
inline bool operator<(const Point& p1, const Point& p2) {
if (p1.x != p2.x) {
return p1.x < p2.x;
} else {
return p1.y < p2.y;
}
}
Boost has a map container that uses one or more indices.
Multi Index Map
What are the requirements on a class that is to be used as the key?
The map needs to be able to tell whether one key's value is less than another key's value: by default this means that (key1 < key2) must be a valid boolean expression, i.e. that the key type should implement the 'less than' operator.
The map template also implements an overloaded constructor which lets you pass-in a reference to a function object of type key_compare, which can implement the comparison operator: so that alternatively the comparison can be implemented as a method of this external function object, instead of needing to be baked in to whatever type your key is of.
This will stuff multiple integer keys into a large integer, in this case, an _int64. It compares as an _int64, AKA long long (The ugliest type declaration ever. short short short short, would only be slightly less elegant. 10 years ago it was called vlong. Much better. So much for "progress"), so no comparison function is needed.
#define ULNG unsigned long
#define BYTE unsigned char
#define LLNG long long
#define ULLNG unsigned long long
// --------------------------------------------------------------------------
ULLNG PackGUID(ULNG SN, ULNG PID, BYTE NodeId) {
ULLNG CompKey=0;
PID = (PID << 8) + NodeId;
CompKey = ((ULLNG)CallSN << 32) + PID;
return CompKey;
}
Having provided this answer, I doubt this is going to work for you, as you need two separate and distinct keys to navigate with in 2 dimensions, X and Y.
On the other hand, if you already have the XY coordinate, and just want to associate a value with that key, then this works spectacularly, because an _int64 compare takes the same time as any other integer compare on Intel X86 chips - 1 clock.
In this case, the compare is 3X as fast on this synthetic key, vs a triple compound key.
If using this to create a sparsely populated spreadsheet, I would RX using 2 distinct trees, one nested inside the other. Make the Y dimension "the boss", and search Y space first to resolution before proceeding to the X dimension. Spreadsheets are taller than they are wide, and you always want the 1st dimension in any compound key to have the largest number of unique values.
This arrangement would create a map for the Y dimension that would have a map for the X dimension as it's data. When you get to a leaf in the Y dimension, you start searching it's X dimension for the column in the spreadsheet.
If you want to create a very powerful spreadsheet system, add a Z dimension in the same way, and use that for, as an example, organizational units. This is the basis for a very powerful budgeting/forecasting/accounting system, one which allows admin units to have lots of gory detail accounts to track admin expenses and such, and not have those accounts take up space for line units which have their own kinds of detail to track.
I think for your use case, std::pair, as suggested in David Norman's answer, is the best solution. However, since C++11 you can also use std::tuple. Tuples are useful if you have more than two keys, for example if you have 3D coordinates (i.e. x, y, and z). Then you don't have to nest pairs or define a comparator for a struct. But for your specific use case, the code could be written as follows:
int main() {
using tup_t = std::tuple<int, int>;
std::map<tup_t, int> m;
m[std::make_tuple(78, 26)] = 476;
tup_t t = { 12, 45 }; m[t] = 102;
for (auto const &kv : m)
std::cout << "{ " << std::get<0>(kv.first) << ", "
<< std::get<1>(kv.first) << " } => " << kv.second << std::endl;
return 0;
}
Output:
{ 12, 45 } => 102
{ 78, 26 } => 476
Note: Since C++17 working with tuples has become easier, espcially if you want to access multiple elements simultaneously.
For example, if you use structured binding, you can print the tuple as follows:
for (auto const &[k, v] : m) {
auto [x, y] = k;
std::cout << "{ " << x << ", " << y << " } => " << v << std::endl;
}
Code on Coliru
Use std::pair. Better even use QHash<QPair<int,int>,int> if you have many of such mappings.
Hope you will find it useful:
map<int, map<int, int>> troyka = { {4, {{5,6}} } };
troyka[4][5] = 7;
An alternative for the top result that is slightly less performant but allows for easier indexing
std::map<int, std::map<int,int>> myMap;
myMap[10][20] = 25;
std::cout << myMap[10][20] << std::endl;
First and foremost, ditch the string and use 2 ints, which you may well have done by now. Kudos for figuring out that a tree is the best way to implement a sparse matrix. Usually a magnet for bad implementations it seems.
FYI, a triple compound key works too, and I assume a pair of pairs as well.
It makes for some ugly sub-scripting though, so a little macro magic will make your life easier. I left this one general purpose, but type-casting the arguments in the macro is a good idea if you create macros for specific maps. The TresKey12 is tested and running fine. QuadKeys should also work.
NOTE: As long as your key parts are basic data types you DON'T need to write anything more. AKA, no need to fret about comparison functions. The STL has you covered. Just code it up and let it rip.
using namespace std; // save some typing
#define DosKeys(x,y) std::make_pair(std::make_pair(x,y))
#define TresKeys12(x,y,z) std::make_pair(x,std::make_pair(y,z))
#define TresKeys21(x,y,z) std::make_pair(std::make_pair(x,y),z))
#define QuadKeys(w,x,y,z) std::make_pair(std::make_pair(w,x),std::make_pair(y,z))
map<pair<INT, pair<ULLNG, ULLNG>>, pIC_MESSAGE> MapMe;
MapMe[TresKey12(Part1, Part2, Part3)] = new fooObject;
If someone wants to impress me, show me how to make a compare operator for TresKeys that doesn't rely on nesting pairs so I can use a single struct with 3 members and use a comparison function.
PS: TresKey12 gave me problems with a map declared as pair,z as it makes x,pair, and those two don't play nice. Not a problem for DosKeys, or QuadKeys. If it's a hot summer Friday though, you may find an unexpected side-effect of typing in DosEquis
... err.. DosKeys a bunch of times, is a thirst for Mexican beer. Caveat Emptor. As Sheldon Cooper says, "What's life without whimsy?".