SQLite in C and supporting REGEXP - c

I'm using sqlite3 in C and I'd like to add support for the REGEXP operator. By default, a user defined function regexp() is not present and calling REGEXP will usually result in an error (according to the SQLite pages).
How do I add a regexp function to support REGEXP? Presumably I will do this via the sqlite3_create_function call, but I don't know what the application-defined regexp() will look like.
Can I use a function from regex.h with sqlite3_create_function and how? Any function I pass to SQLite has to take three arguments of type sqlite3_context*, int, sqlite3_value**. However, the SQLite documents don't seem to explain the meaning of these parameters.
Is there sample code for a C regexp() function?
I've not been able to find much on this using Google or the SQLite pages.

You can also try this:
#include <regex.h>
...
void sqlite_regexp(sqlite3_context* context, int argc, sqlite3_value** values) {
int ret;
regex_t regex;
char* reg = (char*)sqlite3_value_text(values[0]);
char* text = (char*)sqlite3_value_text(values[1]);
if ( argc != 2 || reg == 0 || text == 0) {
sqlite3_result_error(context, "SQL function regexp() called with invalid arguments.\n", -1);
return;
}
ret = regcomp(&regex, reg, REG_EXTENDED | REG_NOSUB);
if ( ret != 0 ) {
sqlite3_result_error(context, "error compiling regular expression", -1);
return;
}
ret = regexec(&regex, text , 0, NULL, 0);
regfree(&regex);
sqlite3_result_int(context, (ret != REG_NOMATCH));
}
...
sqlite3_create_function(*db, "regexp", 2, SQLITE_ANY,0, &sqlite_regexp,0,0)

It would look something like this:
static void user_regexp(sqlite3_context *context, int argc, sqlite3_value **argv)
{
struct re_pattern_buffer buffer;
const char *out;
char *pattern;
char *input_string;
char *result;
struct re_registers regs;
if ((sqlite3_value_type(argv[0]) != SQLITE_TEXT )
|| ((sqlite3_value_type(argv[1]) != SQLITE_TEXT ))
{
sqlite3_result_err("Improper argument types");
return;
}
re_set_syntax(RE_SYNTAX_POSIX_EGREP);
memset(&buffer, 0, sizeof (buffer));
if (!(pattern = strdupa(sqlite3_value_text(argv[0])))
|| !(input_string = strdupa(sqlite3_value_text(argv[1]))))
{
sqlite3_result_err_nomem("Could not allocate memory for strings");
return;
}
if ((out = re_compile_pattern(pattern, strlen(pattern), &buffer))
{
sqlite3_result_err("Could not compile pattern!");
return;
}
if (re_match(&buffer, input_string, strlen(input_string), 0, &regs) < 0)
sqlite3_result_int64(context, 0);
else
{
result = strndupa(input_string + regs.start[0], regs.end[0] - regs.start[0]);
sqlite3_result_text(context, result, NULL, SQLITE_TRANSIENT);
}
}

Okay, a bit too late for this but I'm tempted to post this for all people who are using a C++ Wrapper for the C SQLITE API like the [ SQLiteCpp ] which I am using. This answer assumes that you use SQLiteCpp.
Install Regex for windows binaries from [ here ]. This gives you just enough files ie the regex.h include file and regex2.dll. Do remember to add the path regex.h in your project and have a copy of the dll in the folder containing client executables.
Before building the [ SQLiteCpp ], we need to make some changes to add the regex capabilities to SELECT queries. For this open the Database.cpp file from the [ SQLiteCpp ] project and
Include the regex.h header from the Regex for windows
After all the includes, add below ( of course you can customize to custom fit your needs!) piece of code just below it.
extern "C" {
void sqlite_regexp(sqlite3_context* context, int argc, sqlite3_value** values) {
int ret;
regex_t regex;
char regtext[100];
char* reg = (char*)sqlite3_value_text(values[0]);
sprintf(regtext, ".*%s.*", reg);
//printf("Regtext : %s", regtext);
char* text = (char*)sqlite3_value_text(values[1]);
/* printf("Text : %s\n", text);
printf("Reg : %s\n", reg); */
if (argc != 2 || reg == 0 || text == 0) {
sqlite3_result_error(context, "SQL function regexp() called with invalid arguments.\n", -1);
return;
}
ret = regcomp(&regex, regtext, REG_EXTENDED | REG_NOSUB | REG_ICASE);
if (ret != 0) {
sqlite3_result_error(context, "error compiling regular expression", -1);
return;
}
ret = regexec(&regex, text, 0, NULL, 0);
/* if (ret == 0) {
printf("Found a match. Press any key to continue");
getc(stdin);
}*/
regfree(&regex);
sqlite3_result_int(context, (ret != REG_NOMATCH));
}
}
Now it is time to change the constructors defined in the file. Change those like shown below.
// Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
Database::Database(const char* apFilename,
const int aFlags /*= SQLite::OPEN_READONLY*/,
const int aBusyTimeoutMs/* = 0 */,
const char* apVfs/*= NULL*/) :
mpSQLite(NULL),
mFilename(apFilename)
{
const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs);
//std::cout << "Reached here";
//sqlite3_create_function_v2(mpSQLite, "REGEXP", 2, SQLITE_ANY,&sqlite_regexp, NULL, NULL, NULL,NULL);
sqlite3_create_function(mpSQLite, "regexp", 2, SQLITE_ANY, 0, &sqlite_regexp, 0, 0);
if (SQLITE_OK != ret)
{
const SQLite::Exception exception(mpSQLite, ret); // must create before closing
sqlite3_close(mpSQLite); // close is required even in case of error on opening
throw exception;
}
else {
}
if (aBusyTimeoutMs > 0)
{
setBusyTimeout(aBusyTimeoutMs);
}
}
// Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
Database::Database(const std::string& aFilename,
const int aFlags /* = SQLite::OPEN_READONLY*/,
const int aBusyTimeoutMs/* = 0*/,
const std::string& aVfs/* = "" */) :
mpSQLite(NULL),
mFilename(aFilename)
{
const int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? NULL : aVfs.c_str());
sqlite3_create_function(mpSQLite, "regexp", 2, SQLITE_ANY, 0, &sqlite_regexp, 0, 0);
if (SQLITE_OK != ret)
{
const SQLite::Exception exception(mpSQLite, ret); // must create before closing
sqlite3_close(mpSQLite); // close is required even in case of error on opening
throw exception;
}
if (aBusyTimeoutMs > 0)
{
setBusyTimeout(aBusyTimeoutMs);
}
}
By now, you've some serious regex capabilities with your sqlite. Just build the project.
Write a client program to test the functionality. It can be something like below ( borrowed without shame from SQLiteCpp Example ).
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <SQLiteCpp/SQLiteCpp.h>
#include <SQLiteCpp/VariadicBind.h>
// Notice no sqlite3.h huh?
// Well, this is a C++ wrapper for the SQLITE CAPI afterall.
#ifdef SQLITECPP_ENABLE_ASSERT_HANDLER
namespace SQLite
{
/// definition of the assertion handler enabled when SQLITECPP_ENABLE_ASSERT_HANDLER is defined in the project (CMakeList.txt)
void assertion_failed(const char* apFile, const long apLine, const char* apFunc, const char* apExpr, const char* apMsg)
{
// Print a message to the standard error output stream, and abort the program.
std::cerr << apFile << ":" << apLine << ":" << " error: assertion failed (" << apExpr << ") in " << apFunc << "() with message \"" << apMsg << "\"\n";
std::abort();
}
}
#endif
/// Get example path
static inline std::string getExamplePath()
{
std::string filePath(__FILE__);
return filePath.substr(0, filePath.length() - std::string("Client.cpp").length());
}
/// Example Database
static const std::string filename_example_db3 = getExamplePath() + "/example.db3";
/// Image
static const std::string filename_logo_png = getExamplePath() + "/logo.png";
/// Object Oriented Basic example
class Example
{
public:
//Constructor
Example() :
mDb(filename_example_db3),
// User change the db and tables accordingly
mQuery(mDb, "SELECT id,name FROM lookup WHERE name REGEXP :keyword")
// Open a database file in readonly mode
{
}
virtual ~Example()
{
}
/// List the rows where the "weight" column is greater than the provided aParamValue
void namehaskeyword(const std::string searchfor)
{
std::cout << "Matching results for " << searchfor << "\n";
// Bind the integer value provided to the first parameter of the SQL query
mQuery.bind(1,searchfor); // same as mQuery.bind(1, aParamValue);
// Loop to execute the query step by step, to get one a row of results at a time
while (mQuery.executeStep())
{
std::cout<<mQuery.getColumn(0) << "\t" << mQuery.getColumn(1) << "\n";
}
// Reset the query to be able to use it again later
mQuery.reset();
}
private:
SQLite::Database mDb; ///< Database connection
SQLite::Statement mQuery; ///< Database prepared SQL query
};
int main()
{
// Using SQLITE_VERSION would require #include <sqlite3.h> which we want to avoid: use SQLite::VERSION if possible.
// std::cout << "SQlite3 version " << SQLITE_VERSION << std::endl;
std::cout << "SQlite3 version " << SQLite::VERSION << " (" << SQLite::getLibVersion() << ")" << std::endl;
std::cout << "SQliteC++ version " << SQLITECPP_VERSION << std::endl;
try
{
// Doing a regex query.
Example example;
char wannaquit = 'n';
std::string keyword;
// Deliberate unlimited loop. You implement something sensible here.
while (wannaquit != 'y') {
// Demonstrates the way to use the same query with different parameter values
std::cout << "Enter the keyword to search for : ";
std::getline(std::cin, keyword);
example.namehaskeyword(keyword);
}
}
catch (std::exception& e)
{
std::cout << "SQLite exception : " << e.what() << std::endl;
return EXIT_FAILURE; // unexpected error : exit the example program
}
return EXIT_SUCCESS;
}
Note : This assumes that the database is in the same folder as your cpp

Related

XML CharacterDataHandler callback unpextedly called multiple times

I'm learning about libexpat. I cobbled together this example for basic familiarity using the API:
The Code:
#include <stdio.h>
#include <expat.h>
#include <string.h>
#include <iostream>
void start(void* userData, const char* name, const char* argv[])
{
std::cout << "name: " << name << std::endl;
int i = 0;
while (argv[i])
{
std::cout << "argv[" << i << "] == " << argv[i++] << std::endl;
}
}
void end(void* userData, const char* name)
{
}
void value(void* userData, const char* val, int len)
{
char str[len+1];
strncpy(str, val, len);
str[len] = '\0';
std::cout << "value: " << str << std::endl;
}
int main(int argc, char* argv[], char* envz[])
{
XML_Parser parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, start, end);
XML_SetCharacterDataHandler(parser, value);
int bytesRead = 0;
char val[1024] = {};
FILE* fp = fopen("./catalog.xml", "r");
std::cout << "fp == 0x" << (void*)fp << std::endl;
do
{
bytesRead = fread(val, 1, sizeof(val), fp);
std::cout << "In while loop bytesRead==" << bytesRead << std::endl;
if (0 == XML_Parse(parser, val, bytesRead, (bytesRead < sizeof(val))))
{
break;
}
}
while (1);
XML_ParserFree(parser);
std::cout << __FUNCTION__ << " end" << std::endl;
return 0;
}
catalog.xml:
<CATALOG>
<CD key1="value1" key2="value2">
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<YEAR>1995</YEAR>
</CD>
</CATALOG>
Makefile:
xml: xml.o
g++ xml.o -lexpat -o xml
xml.o: main.cpp Makefile
g++ -g -c main.cpp -o xml.o
Output:
fp == 0x0x22beb50
In while loop bytesRead==148
name: CATALOG
value:
value:
name: CD
argv[1] == key1
argv[2] == value1
argv[3] == key2
argv[4] == value2
value:
value:
name: TITLE
value: Empire Burlesque
value:
value:
name: ARTIST
value: Bob Dylan
value:
value:
name: YEAR
value: 1995
value:
value:
value:
In while loop bytesRead==0
main end
Question:
From the output, it appears that the callback I installed with XML_SetCharacterDataHandler() gets called twice for the CATALOG,, CD, TITLE, and ARTIST xml tags, and then multiple times for the YEAR tag - can someone explain this behavior? From the noted catalog.xml, it's not clear to me why there are (or would ever be) multiple values associated with any XML tags.
Thank you.
Citation:
Credit to this site for the basis of the above sample code.
The expat parser may split text nodes into multiple calls to the character data handler. To properly handle text nodes you must accumulate text over multiple calls and process it when receiving the "end" event for the containing tag.
This is true in general, even across different parsers and different languages -- i.e. the same thing is true in Java.
See for instance http://marcomaggi.github.io/docs/expat.html#using-comm
A common first–time mistake with any of the event–oriented interfaces to an XML parser is to expect all the text contained in an element to be reported by a single call to the character data handler. Expat, like many other XML parsers, reports such data as a sequence of calls; there's no way to know when the end of the sequence is reached until a different callback is made.
Also from the expat documentation
A single block of contiguous text free of markup may still result in a sequence of calls to this handler. In other words, if you're searching for a pattern in the text, it may be split across calls to this handler.

sscanf with double quotes

I'm using an Arduino and Open Weather Map API to create a weather station, but I'm having serious trouble to parse the response into something useful with sscanf.
Here is one response example:
{"coord":{"lon":-0.13,"lat":51.51},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}],"base":"cmc stations","main":{"temp":14.17,"pressure":1012,"humidity":74,"temp_min":13,"temp_max":15.8},"wind":{"speed":4.6,"deg":150},"clouds":{"all":0},"dt":1459602835,"sys":{"type":1,"id":5091,"message":0.0059,"country":"GB","sunrise":1459575095,"sunset":1459622222},"id":2643743,"name":"London","cod":200}
I would like to parse the weather info (Clear) from:
"weather":[{"id":800,"main":"Clear",
And the temp info (14) from:
"main":{"temp":14.17,
This is the code, I'm using:
if (character == '}') { // Just a delimiter
if (strstr(response, "\"weather\":[{")) { // to confirm that the string was found
sscanf(response, ",main\":%s,", weather);
Serial.printfn("\r\nfound weather = %s"), weather;
}
else if (strstr(response, "\"main\":{\"temp\":")) { // to confirm that the string was found
sscanf(response, "temp\":%2s,", temp);
Serial.printfn("\r\nfound temp = %s"), temp;
}
memset(response, 0, sizeof(response));
idx = 0;
}
But the sscanf seens to not even beeing working, since it always print the whole weather / temp strings 32 bytes long.
found weather = ,"weather":[{"id":800,"main":"Clear","description":
found temp = ],"base":"cmc stations","main":{"temp":14.17,"pressure":1011,"humi
Anyone have any clue how to parse these string using sscanf?
Here is an example. Translate it to any C-Dialect you need.
#include <cstdio>
#include <cstring>
#include <iostream>
const char* haystack = "\"weather\":[{\"id\":800,\"main\":\"Clear\",";
const char* needle = "\"main\":";
int main()
{
std::cout << "Parsing string: '" << haystack << "'\n";
if (const char* cursor = strstr(haystack, needle)) {
char buffer[100];
if (sscanf(cursor, "\"main\":\"%99[^\"]\",", buffer))
std::cout << "Parsed string: '" << buffer << "'\n";
else
std::cout << "Parsing error!\n";
} else {
std::cout << "Could not find '" << needle << "' in '" << haystack << "'\n";
}
}
if Serial.printfn is a pointer to a function which work like printf(), then
Serial.printfn("\r\nfound weather = %s"), weather;
is undefined Behavior, and may print what you see.
you should use
Serial.printfn("\r\nfound weather = %s", weather);

SQL Server CE 3.5 update row error DB_E_ERRORSOCCURRED column error is DBSTATUS_E_SCHEMAVIOLATION

I am investigating moving a small and simple SQL Server database to SQL Server CE and am currently using a small prototype to investigate basic operations with SQL Server CE with the following operations in mind: (1) programmatically create a table, (2) insert new records, (3) read existing records, and (4) update existing records.
The prototype is having a problem with updating existing records when using the Accessor and the bound members of the Accessor struct. The select statement works correctly returning the row along with the data. I can update the Accessor bound members however when I use the SetData() method to update the row, the HRESULT value returned is DB_E_ERRORSOCCURRED. I then examine the DBSTATUS variables and I can see the error code of DBSTATUS_E_SCHEMAVIOLATION.
What does DBSTATUS_E_SCHEMAVIOLATION mean and what do I need to change so that SetData() works?
If I modify the SQL query used in the OLEDB so that rather than doing a SELECT I instead do an UPDATE the row selected by the WHERE clause of the UPDATE is modified correctly. The problem appears to be with the SetData() functionality and the binding logic. When I have done the same thing with SQL Server Express, I do not see an error. I see the same error with both SQL Server CE 3.5 and SQL Server Mobile for Visual Studio 2005.
In the output window of the Visual Studio 2005 IDE I see the following lines. Two of the lines marked with <<<<< ATLTRACE2 are output from ATLTRACE2 macros to show the individual column status values. From what I can find on the internet, the First-chance exception log is a warning that can be ignored.
First-chance exception at 0x7c812fd3 in dblist_ce.exe: Microsoft C++ exception: long at memory location 0x0012f698..
OLE DB Error Record dump for hr = 0x80040e21
The thread 'Win32 Thread' (0x16dc) has exited with code 0 (0x0).
Row #: 0 Source: "Microsoft Cursor Engine" Description: "Multiple-step operation generated errors. Check each status value." Help File: "(null)" Help Context: 0 GUID: {00000000-0000-0000-0000-000000000000}
OLE DB Error Record dump end
myTable.m_dwIdNumberStatus = 8 <<<<< ATLTRACE2
myTable.m_dwCountStatus = 11 <<<<< ATLTRACE2
The two status values (m_dwIdNumberStatus and m_dwCountStatus) have values from an enum and the above two values represent DBSTATUS_E_UNAVAILABLE = 8 and DBSTATUS_E_SCHEMAVIOLATION = 11. The status for IdNumber is DBSTATUS_E_UNAVAILABLE because I am setting it to be ignored before doing the SetData().
The source code for the prototype follows. What this does is to create the SQL Server CE database file if it does not exist and then fills it with a set of rows and then tries to do an update on one particular row.
// dblist_ce.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <string>
#include <iostream>
#define SQLSERVER_MOBILE L"Provider=Microsoft.SQLSERVER.MOBILE.OLEDB.3.0;Data Source=C:\\MyDatabase3.sdf"
#define SQLSERVER_CE_35 L"Provider=Microsoft.SQLSERVER.CE.OLEDB.3.5;Data Source=C:\\MyDatabase35.sdf"
#define SQL_SERVER_CONNECT_STRING SQLSERVER_MOBILE
#define SQL_SERVER_CE_FILENAME "C:\\MyDatabase3.sdf"
#if 0
#include "Table_1.h"
#else
// contents of include file Table_1.h follow
// Table_1.h : Declaration of the CTable_1
// code generated on Saturday, April 26, 2014, 11:23 AM
class CTable_1Accessor
{
public:
TCHAR m_IdNumber[11];
LONG m_Count;
// The following wizard-generated data members contain status
// values for the corresponding fields in the column map. You
// can use these values to hold NULL values that the database
// returns or to hold error information when the compiler returns
// errors. See Field Status Data Members in Wizard-Generated
// Accessors in the Visual C++ documentation for more information
// on using these fields.
// NOTE: You must initialize these fields before setting/inserting data!
DBSTATUS m_dwIdNumberStatus;
DBSTATUS m_dwCountStatus;
// The following wizard-generated data members contain length
// values for the corresponding fields in the column map.
// NOTE: For variable-length columns, you must initialize these
// fields before setting/inserting data!
DBLENGTH m_dwIdNumberLength;
DBLENGTH m_dwCountLength;
void GetRowsetProperties(CDBPropSet* pPropSet)
{
bool bRet;
bRet = pPropSet->AddProperty(DBPROP_CANFETCHBACKWARDS, true, DBPROPOPTIONS_OPTIONAL);
bRet = pPropSet->AddProperty(DBPROP_CANSCROLLBACKWARDS, true, DBPROPOPTIONS_OPTIONAL);
bRet = pPropSet->AddProperty(DBPROP_IGetRow, true, DBPROPOPTIONS_OPTIONAL);
bRet = pPropSet->AddProperty(DBPROP_IRowsetChange, true, DBPROPOPTIONS_OPTIONAL);
bRet = pPropSet->AddProperty(DBPROP_IRowsetUpdate, true, DBPROPOPTIONS_OPTIONAL);
bRet = pPropSet->AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE);
}
HRESULT OpenDataSource()
{
CDataSource _db;
HRESULT hr;
hr = _db.OpenFromInitializationString(SQL_SERVER_CONNECT_STRING);
if (FAILED(hr))
{
#ifdef _DEBUG
AtlTraceErrorRecords(hr);
#endif
return hr;
}
return m_session.Open(_db);
}
void CloseDataSource()
{
m_session.Close();
}
operator const CSession&()
{
return m_session;
}
CSession m_session;
DEFINE_COMMAND_EX(CTable_1Accessor, L" \
SELECT \
IdNumber, \
Count \
FROM Table_1")
// In order to fix several issues with some providers, the code below may bind
// columns in a different order than reported by the provider
BEGIN_COLUMN_MAP(CTable_1Accessor)
COLUMN_ENTRY_LENGTH_STATUS(1, m_IdNumber, m_dwIdNumberLength, m_dwIdNumberStatus)
COLUMN_ENTRY_LENGTH_STATUS(2, m_Count, m_dwCountLength, m_dwCountStatus)
END_COLUMN_MAP()
};
class CTable_1 : public CCommand<CAccessor<CTable_1Accessor> >
{
public:
HRESULT OpenAll()
{
HRESULT hr;
hr = OpenDataSource();
if (FAILED(hr))
return hr;
__if_exists(GetRowsetProperties)
{
CDBPropSet propset(DBPROPSET_ROWSET);
__if_exists(HasBookmark)
{
if( HasBookmark() )
propset.AddProperty(DBPROP_IRowsetLocate, true);
}
GetRowsetProperties(&propset);
return OpenRowset(&propset);
}
__if_not_exists(GetRowsetProperties)
{
__if_exists(HasBookmark)
{
if( HasBookmark() )
{
CDBPropSet propset(DBPROPSET_ROWSET);
propset.AddProperty(DBPROP_IRowsetLocate, true);
return OpenRowset(&propset);
}
}
}
return OpenRowset();
}
HRESULT OpenRowset(DBPROPSET *pPropSet = NULL)
{
HRESULT hr = Open(m_session, NULL, pPropSet);
#ifdef _DEBUG
if(FAILED(hr))
AtlTraceErrorRecords(hr);
#endif
return hr;
}
void CloseAll()
{
Close();
ReleaseCommand();
CloseDataSource();
}
};
// ------ End of the content from include file Table_1.h
#endif
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hrResult = OleInitialize(NULL);
switch (hrResult)
{
case S_OK:
break;
default:
std::cout << "Ole Initialization Failed " << hrResult << std::endl;
return 1;
}
HRESULT hr;
CTable_1 myTable;
bool myTableNew = false;
hr = myTable.OpenAll ();
AtlTraceErrorRecords(hr);
if (hr == S_OK) {
int nItem = 0;
for (nItem = 0, hr = myTable.MoveFirst(); hr == S_OK; hr = myTable.MoveNext())
{
char szValueChar[12] = {0};
for (int i = 0; i < 10; i++) szValueChar[i] = (char)myTable.m_IdNumber[i];
std::string sTemp (szValueChar);
std::cout << nItem << " -> " << sTemp << " : " << myTable.m_Count << std::endl;
nItem++;
}
myTable.Close(); // close this row set.
} else if (hr == E_FAIL) {
FILE *hFile = fopen (SQL_SERVER_CE_FILENAME, "w");
if (hFile) {
fclose(hFile);
hr = myTable.OpenAll ();
if (hr == E_FAIL)
return 0;
}
}
if (hr == DB_E_NOTABLE) {
// The database file is empty meaning that there are no tables defined
// so we will create the table that we want to use.
myTable.Close(); // close this row set.
CDBPropSet m_pPropSet(DBPROPSET_ROWSET);
myTable.GetRowsetProperties (&m_pPropSet);
TCHAR *tcsQuery = L"create table Table_1 ([IdNumber] nchar(10) not null, [Count] int not null)";
hr = myTable.Open (myTable.m_session, tcsQuery, &m_pPropSet, NULL, DBGUID_DEFAULT, false);
myTable.Close(); // close this row set.
myTableNew = true;
}
CDBPropSet m_pPropSet(DBPROPSET_ROWSET);
myTable.GetRowsetProperties (&m_pPropSet);
TCHAR tcsQuery[256];
if (myTableNew) {
struct {
TCHAR IdNumber[11];
int iCount;
} myInsertData[] = {
{L"0000000101", 1001},
{L"0000000102", 1002},
{L"0000000103", 1003},
{L"0000000104", 1004},
{L"0000000105", 1005},
{L"0000000106", 1006},
{L"0000000107", 1007},
{L"0000000108", 1008},
{L"0000000109", 1009},
{L"0000000120", 1010}
};
std::cout << "-- New table so insert standard rows " << std::endl;
for (int i = 0; i < sizeof(myInsertData)/sizeof(myInsertData[0]); i++) {
_swprintf (tcsQuery, L"INSERT INTO Table_1 ( [IdNumber], [Count] ) VALUES ('%s', %d)", myInsertData[i].IdNumber, myInsertData[i].iCount);
hr = myTable.Open (myTable.m_session, tcsQuery, &m_pPropSet, NULL, DBGUID_DEFAULT, false);
myTable.Close(); // close this row set.
}
}
// Lets print out a list of the rows that we currently have in the database
wcscpy (tcsQuery, L"SELECT [IdNumber], [Count] from Table_1");
hr = myTable.Open (myTable.m_session, tcsQuery, &m_pPropSet, NULL, DBGUID_DEFAULT, true);
if (hr == S_OK) {
int nItem = 0;
for (nItem = 0, hr = myTable.MoveFirst(); hr == S_OK; hr = myTable.MoveNext())
{
char szValueChar[12] = {0};
for (int i = 0; i < 10; i++) szValueChar[i] = (char)myTable.m_IdNumber[i];
std::string sTemp (szValueChar);
std::cout << nItem << " -> " << sTemp << " : " << myTable.m_Count << std::endl;
nItem++;
}
myTable.Close(); // close this row set.
}
std::cout << " -- After insert now list the rows we have inserted" << std::endl;
wcscpy (tcsQuery, L"SELECT [IdNumber], [Count] from Table_1 where [IdNumber] = '0000000103'");
// wcscpy (tcsQuery, L"UPDATE Table_1 SET [Count]=[Count] + 1 where [IdNumber] = '0000000103'");
hr = myTable.Open (myTable.m_session, tcsQuery, &m_pPropSet, NULL, DBGUID_DEFAULT, true);
AtlTraceErrorRecords(hr);
if (hr == S_OK) {
if ((hr = myTable.MoveFirst()) == S_OK)
{
char szValueChar[12] = {0};
for (int i = 0; i < 10; i++) szValueChar[i] = (char)myTable.m_IdNumber[i];
std::string sTemp (szValueChar);
std::cout << " -> " << sTemp << " : " << myTable.m_Count << std::endl;
int iCountTemp = myTable.m_Count++;
std::cout << " increment count from " << iCountTemp << " to " << myTable.m_Count << std::endl;
myTable.m_dwIdNumberStatus = DBSTATUS_S_IGNORE;
myTable.m_dwCountStatus = DBSTATUS_S_OK;
hr = myTable.SetData ();
AtlTraceErrorRecords(hr);
if (hr != S_OK) {
ATLTRACE2(" myTable.m_dwIdNumberStatus = %d\n", myTable.m_dwIdNumberStatus);
ATLTRACE2(" myTable.m_dwCountStatus = %d\n", myTable.m_dwCountStatus);
if (myTable.m_dwIdNumberStatus != DBSTATUS_S_OK) {
std::cout << " error: m_dwIdNumberStatus = "<< myTable.m_dwIdNumberStatus << std::endl;
}
if (myTable.m_dwCountStatus != DBSTATUS_S_OK) {
std::cout << " error: m_dwCountStatus = "<< myTable.m_dwCountStatus << std::endl;
}
}
} else {
AtlTraceErrorRecords(hr);
}
}
myTable.Close(); // close this row set.
OleUninitialize ();
return 0;
}
MSDN says that DBSTATUS_E_SCHEMAVIOLATION means that
The data value violated the schema's constraint for the column.
Just search for DBSTATUS_E_SCHEMAVIOLATION on that page.
It is strange because the only constraint that you have for the Count column is "not null".
Personally, I never used OLE DB with Compact Edition of SQL Server, and I never tried to update rows like you do. I put all my T-SQL code in stored procedures and call them using "call" or "exec". Inside stored procedures I use standard UPDATE statements.
In your case it is very likely that you are right about the type of the cursor. When you call myTable.Open to run the query SELECT [IdNumber], [Count] from Table_1 where [IdNumber] = '0000000103' it is very likely that you are getting a read-only cursor. I don't know how to check it, but in your place I would try to find a way to confirm whether the cursor is updatable in the first place.

how to load .dll which is in different location in .exe

i have implemented a simple dll project to add two numbers in visual studio 2010.i have implemented add function in a dll file and have written .def file to export the add function.
secondly, i have created another console application using visual studio 2010 which calls the add function that is created in the dll file above and in different location.
Issue is how to load this dll file which is in different location in to .exe file.
I think you need to use LoadLibrary
HMODULE hmDLL = LoadLibrary(TEXT("path\\to\\your\\.dll"));
You might have to use GetProcAddress to locate the functions you wish to call from your DLL.
typedef YourFuncReturnType (*YourFuncPtr)(FunctionArgType1, FunctionArgType2);
YourFuncPtr ptr = (YourFuncPtr)GetProcAddress(hmDLL, "YourFunctionName");
YourFunctionReturnType ret = ptr(arg1, arg2);
And FreeLibrary when you're finished with it
FreeLibrary(hmDLL);
Let's say I have a DLL, and in that DLL I have a function, Foo.
DLL.cpp
DLLEXPORT int Foo(int a, int b)
{
return a + b;
}
And I have another project which I wish to access the function Foo from my DLL.
Program.cpp
#include <Windows.h>
#include <iostream>
// Define the pointer type for the function Foo
typedef int (*funcptr)(int, int);
char g_szDLLPath[] = "path\\to\\foo.dll";
int main() {
HMODULE hmDLL = LoadLibrary(g_szDLLPath);
if(NULL != hmDLL) {
funcptr fooPtr = (funcptr)GetProcAddress(hmDLL, "Foo");
if(NULL != fooPtr) {
int result = fooPtr(5, 10);
if(result == 15)
std::cout << "Yay! Foo worked as expected!" << std::endl;
else
std::cout << "What the deuce! Foo returned " << result << std::endl;
result = fooPtr(10, 10);
if(result == 20)
std::cout << "Yay! Foo worked as expected!" << std::endl;
else
std::cout << "What the deuce! Foo returned " << result << std::endl;
} else {
perror("Error Locating Foo");
return -1;
}
} else {
perror("Error Loading DLL");
return -1;
}
return 0;
}

How create a simple program using threads in C?

I'm new in C development, I know just the basics and I need to create a program that discover a simple hash password like this one:
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <crypt.h>
#include <stdlib.h>
#define SIZE_HASH 256
#define SIZE_PASSWORD 4
/* Get the hash from a passwod and put the result in hash. The array hash shoud have at lest 14 elements. */
void calculate_hash_password(const char *password, char *hash);
void increment_password(char *password);
void test_password(const char *p_hash, const char *password);
int main(int argc, char *argv[]) {
int i;
char password[SIZE_PASSWORD + 1];
if (argc != 2) {
printf("Use: %s <hash>", argv[0]);
return 1;
}
for (i = 0; i < SIZE_PASSWORD; i++) {
password[i] = 'a';
}
password[SIZE_PASSWORD] = '\0';
while (1) {
test_password(argv[1], password);
increment_password(password);
}
return 0;
}
void test_password(const char *p_hash, const char *password) {
char hash_calculado[SIZE_HASH + 1];
calculate_hash_password(password, hash_calculado);
if (!strcmp(p_hash, hash_calculado)) {
printf("Achou! %s\n", password);
exit(0);
}
}
void increment_password(char *password) {
int i;
i = SIZE_PASSWORD - 1;
while (i >= 0) {
if (password[i] != 'z') {
password[i]++;
i = -2;
} else {
password[i] = 'a';
i--;
}
}
if (i == -1) {
printf("Não achou!\n");
exit(1);
}
}
void calculate_hash_password(const char *password, char *hash) {
struct crypt_data data;
data.initialized = 0;
strcpy(hash, crypt_r(password, "aa", &data));
}
I must do the same thing as this one but using threads in C.
How can I do that ?
EDIT
Using threads to hash passwords is not a particularly intuitive or obviously useful approach, so it is not clear why anyone would want to do that.
Presumably the calculation for hashing is split up in some way: perhaps one thread processes passwords beginning with A through M and another does N through Z, or some such partitioning. One idea would be to run the same function multiple times with a parameter which determines which partition to execute. Here is a simple, functioning program which demonstrates the framework.
#include <iostream>
#include <pthread.h>
static void *calc_func (void *arg)
{
int param = (int) arg;
if (param == 1)
{
// do first partition of calculation
// ...
std::cout << "partition 1" << std::endl;
}
else
{
// do second partition of calculation
// ...
std::cout << "partition 2" << std::endl;
}
}
int main (...)
{
// ...
pthread_t threadh[2];
if (pthread_create (&threadh[0], NULL, calc_func, (void *)1) != 0)
{
std::cerr << "error creating thread 1" << std::endl;
}
if (pthread_create (&threadh[1], NULL, calc_func, (void *)2) != 0)
{
std::cerr << "error creating thread 2" << std::endl;
}
// wait for threads to exit
pthread_join (threadh[0], NULL);
pthread_join (threadh[1], NULL);
return 0;
}
To build it on Linux using gcc, use the command g++ -pthread filename.c++ -o filename
On a Linux shell execute:
man pthread_create
Read it carefully, and notice that provides a very descriptive example, on how to use threads. See also the man pages of the functions in the SEE ALSO section.
If you are on windows you can see the decomentation of pthreads-win32 here
After that you have to decide which part(s) of your code can be parallelized and assign that code to different threads.

Resources