I have such working code:
const char sql[] = "INSERT INTO test (pk, geom) VALUES (?, ?)";
sqlite3_stmt *stmt;
sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
for (...) {
sqlite3_reset (stmt);
sqlite3_clear_bindings (stmt);
int blob_size = ..;
unsigned char *blob = malloc(blob_size);
sqlite3_bind_int64 (stmt, 1, pk);
sqlite3_bind_blob (stmt, 2, blob, blob_size, free);
sqlite3_step (stmt);
}
I wonder is it possible to not allocate and free on every step of cycle?
If I pass SQLITE_STATIC instead of free to sqlite3_bind_blob
and call free after end of cycle is this code still become valid?
const char sql[] = "INSERT INTO test (pk, geom) VALUES (?, ?)";
sqlite3_stmt *stmt;
sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
int capacity = 1024;
unsigned char *blob = malloc(capacity);
for (...) {
sqlite3_reset (stmt);
sqlite3_clear_bindings (stmt);
int blob_size = ..;
if (capacity < blob_size) {
blob = realloc(blob, blob_size);
capacity = blob_size;
}
sqlite3_bind_int64 (stmt, 1, pk);
sqlite3_bind_blob (stmt, 2, blob, blob_size, SQLITE_STATIC);
sqlite3_step (stmt);
}
free(blob);
Using SQLITE_STATIC requires that the value stays valid as long as the statement might access it.
Your code should be valid; but to be sure, move the call to sqlite3_clear_bindings() (and the reset) to the end of the loop.
Question: If I pass SQLITE_STATIC instead of free to sqlite3_bind_blob and call free after end of cycle is this code still become valid?
Answer: No.
SQLite documentation on sqlite3_bind_blob():
If the fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its own private copy of the data immediately, before the sqlite3_bind_*() routine returns.
This implies that when the fifth argument does not have this value (in particular, when the fifth argument has the value SQLITE_STATIC), SQLite may still require the data after the routine returns. In that case, no guarantees are made about how long SQLite may require the data (except, presumably, SQLite will not require anything after sqlite3_close() is called).
From the SQLite docs:
The fifth argument to the BLOB and string binding interfaces is a destructor used to dispose of the BLOB or string after SQLite has finished with it. The destructor is called to dispose of the BLOB or string even if the call to bind API fails. If the fifth argument is the special value SQLITE_STATIC, then SQLite assumes that the information is in static, unmanaged space and does not need to be freed. If the fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its own private copy of the data immediately, before the sqlite3_bind_*() routine returns.
If you're reallocating the memory, you should use SQLITE_TRANSIENT. That way SQLite won't make any assumptions about being able to rely on that memory, it will make its own copy.
Note that the docs don't say anything about exactly when the specified destructor (if any) is called -- only that it is called when SQLite is finished with the BLOB. If you don't want to use SQLITE_TRANSIENT, then you should NOT use SQLITE_STATIC, because SQLite may or may not assume that the memory is available when it actually isn't anymore.
Related
I am using the jansson library for a C project.
I have some problem understanding how to use the decref. Shall it be used after each new json_t parameter or not? As I understand jansson will borrow references to make this simpler.
If I run this program and check the values of a_id and a_test they are the same. I expected error or null for a_test.
I tried the same idea but then I added decref for json_acc and json_param but it crashed before I could even read the 1:th value. I was assuming a crash but not until a_test.
This is part of a bigger project but I try to add an example to show the essentials.
API side:
json_t* parObj;
void loadFile(char* path)
{
json_error_t error;
parObj = json_load_file(path, 0, &error);
}
int getAccountId(char* id)
{
json_t* json_acc = json_object_get(parObj, "accounts");
json_t* json_param = json_object_get(json_acc, id);
return json_integer_value(json_param);
}
void cleanJson()
{
json_decref(parObj);
}
Caller side:
loadFile("/home/jacob/accountDump.json");
int a_id = getAccountId("10");
cleanJson();
int a_test = getAccountId("10");
I did misunderstood how it is supposed to work, I assumed that decref would also set the memory to zero.
The API will remove the references and make it a free memory but as long as no one writes there or memset it to zero and the pointer is not set to null I can still read the values from that pointer.
I'm writing an application that uses the wxSQLite3 library, which is a wrapper around libsqlite3 for the wxWidgets cross-platform GUI programming framework. When attempting to reuse a prepared statement, a wxSQLite3Exception is thrown.
This example illustrates the problem:
#include <wx/string.h>
#include <wx/wxsqlite3.h>
int main() {
wxSQLite3Database::InitializeSQLite();
//create in-memory test database & populate it
wxSQLite3Database db;
db.Open(wxT(":memory:"));
db.ExecuteUpdate(wxT("CREATE TABLE SimpleTable (id INT PRIMARY KEY, val INT);"));
db.ExecuteUpdate(wxT("INSERT INTO SimpleTable VALUES (1, 10);"));
db.ExecuteUpdate(wxT("INSERT INTO SimpleTable VALUES (2, 20);"));
//create a prepared statement we can reuse
wxSQLite3Statement stmt;
stmt = db.PrepareStatement(wxT("SELECT * FROM SimpleTable WHERE id = ?;"));
//first use of statement (works)
stmt.Bind(1, 1);
wxSQLite3ResultSet r_set = stmt.ExecuteQuery();
if (r_set.NextRow()) {
wxPrintf(wxT("id: %i value: %i\n"), r_set.GetInt(wxT("id")), r_set.GetInt(wxT("val")));
}
r_set.Finalize();
//reset and reuse statement
stmt.Reset();
stmt.Bind(1, 2); //**EXCEPTION THROWN HERE**
wxSQLite3ResultSet r_set2 = stmt.ExecuteQuery();
if (r_set2.NextRow()) {
wxPrintf(wxT("id: %i value: %i\n"), r_set2.GetInt(wxT("id")), r_set2.GetInt(wxT("val")));
}
r_set2.Finalize();
//cleanup
stmt.Finalize();
db.Close();
wxSQLite3Database::ShutdownSQLite();
return 0;
}
The exception handling was removed for brevity, but the message from the exception is:
WXSQLITE_ERROR[1000]: Statement not accessible
I wrote roughly equivalent code in plain C using libsqlite3 and it ran without problem. Does anyone know what I'm doing wrong, or if this is a bug of some sort in wxSQLite3? Thank you in advance for your help!
In SQLite itself, a statement and a result set actually are the same object.
wxSQLite3 uses reference counting so that the statement is freed only when the last wxSQLite3Statement or wxSQLite3ResultSet object is freed.
This happens automatically in the respective destructors.
However, calling Finalize() explicitly bypasses the reference counting.
While not necessary, if you want to ensure that wxSQLite3ResultSet resources are freed correctly before the next statement execution, just destruct this object:
wxSQLite3Statement stmt = ...;
...
{
wxSQLite3ResultSet r_set = stmt.ExecuteQuery();
... r_set.NextRow() ...
// r_set destructed here
}
...
As long as you intend to reuse a prepared SQL statement, that is, to reset the statement and to bind new values to statement variables, you must not call method Finalize - neither on the prepared statement object itself nor on a result set retrieved from that statement.
As the method name, Finalize, suggests, the method finalizes the underlying SQLite statement object by calling sqlite3_finalize (quotation from the SQLite docs: "The sqlite3_finalize() function is called to delete a prepared statement.") After the underlying SQLite statement object has been deleted, it obviously can't be accessed anymore. Therefore you get the exception.
Usually you don't need to call method Finalize explicitly. wxSQLite3 takes care of finalizing statements through reference counting.
I'm trying to share a variable with c and tcl, the problem is when i try to read the variable in the c thread from tcl, it causes segmentation error, i'm not sure this is the right way to do it, but it seems to work for ints. The part that is causing the segmentation fault is this line is when i try to print "Var" but i want to read the variable to do the corresponding action when the variable changes.
Here is the C code that i'm using
void mode_service(ClientData clientData) {
while(1) {
char* Var = (char *) clientData;
printf("%s\n", Var);
usleep(100000); //100ms
}
}
static int mode_thread(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
Tcl_ThreadId id;
ClientData limitData;
limitData = cdata;
id = 0;
Tcl_CreateThread(&id, mode_service, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);
printf("Tcl_CreateThread id = %d\n", (int) id);
// Wait thread process, before returning to TCL prog
int i, aa;
for (i=0 ; i<100000; i++) {aa = i;}
// Return thread ID to tcl prog to allow mutex use
Tcl_SetObjResult(interp, Tcl_NewIntObj((int)id));
printf("returning\n");
return TCL_OK;
}
int DLLEXPORT Modemanager_Init(Tcl_Interp *interp){
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
if (Tcl_PkgProvide(interp, "PCIe", "1.0") == TCL_ERROR) {
return TCL_ERROR;
}
// Create global Var
int *sharedPtr=NULL;
//sharedPtr = sharedPtr = (char *) Tcl_Alloc(sizeof(char));
Tcl_LinkVar(interp, "mode", (char *) &sharedPtr, TCL_LINK_STRING);
Tcl_CreateObjCommand(interp, "mode_thread", mode_thread, sharedPtr, NULL);
return TCL_OK;
}
In the tcl code, i'm changing the variable mode whenever the user presses a button for example:
set mode "Idle"
button .startSamp -text "Sample Start" -width 9 -height 3 -background $btnColor -relief flat -state normal -command {set mode "Sampling"}
set threadId [mode_thread]
puts "Created thread $threadId, waiting"
Your code is a complete mess! You need to decide what you are doing and then do just that. In particular, you are using Tcl_LinkVar so you need to decide what sort of variable you are linking to. If you get a mismatch between the storage, the C access pattern and the declared semantic type, you'll get crashes.
Because your code is in too complicated a mess for me to figure out exactly what you want to do, I'll illustrate with less closely related examples. You'll need to figure out from them how to change things in your code to get the result you need.
Linking Integer Variables
Let's do the simple case: a global int variable (declared outside any function).
int sharedVal;
You want your C code to read that variable and get the value. Easy! Just read it as it is in scope. You also want Tcl code to be able to write to that variable. Easy! In the package initialization function, put this:
Tcl_LinkVar(interp /* == the Tcl interpreter context */,
"sharedVal" /* == the Tcl name */,
(char *) &sharedVal /* == pointer to C variable */,
TCL_LINK_INT /* == what is it! An integer */);
Note that after that (until you Tcl_UnlinkVar) whenever Tcl code reads from the Tcl variable, the current value will be fetched from the C variable and converted.
If you want that variable to be on the heap, you then do:
int *sharedValPtr = malloc(sizeof(int));
C code accesses using *sharedValPtr, and you bind to Tcl with:
Tcl_LinkVar(interp /* == the Tcl interpreter context */,
"sharedVal" /* == the Tcl name */,
(char *) sharedValPtr /* == pointer to C variable */,
TCL_LINK_INT /* == what is it! An integer */);
Linking String Variables
There's a bunch of other semantic types as well as TCL_LINK_INT (see the documentation for a list) but they all follow that pattern except for TCL_LINK_STRING. With that, you do:
char *sharedStr = NULL;
Tcl_LinkVar(interp, "sharedStr", (char *) &sharedStr, TCL_LINK_STRING);
You also need to be aware that the string will always be allocated with Tcl_Alloc (which is substantially faster than most system memory allocators for typical Tcl memory usage patterns) and not with any other memory allocator, and so will also always be deallocated with Tcl_Free. Practically, that means if you set the string from the C side, you must use Tcl_Alloc to allocate the memory.
Posting Update Notifications
The final piece to note is when you set the variable from the C side but want Tcl to notice that the change has set (e.g., because a trace has been set or because you've surfaced the value in a Tk GUI), you should do Tcl_UpdateLinkedVar to let Tcl know that a change has happened that it should pay attention to. If you never use traces (or Tk GUIs, or the vwait command) to watch the variable for updates, you can ignore this API call.
Donal's answer is correct, but I try to show you what you did with your ClientData.
To clarify: All (or almost all, Idk) Tcl functions that take a function pointer also take a parameter of type ClientData that is passed to your function when Tcl calls it.
Let's take a look at this line:
Tcl_CreateObjCommand(interp, "mode_thread", mode_thread, NULL, NULL);
// ------------------------------------------------------^^^^
You always pass NULL as ClientData to the mode_thread function.
In the mode_thread function you use the passed ClientData (NULL) to pass it as ClientData to the new Thread:
limitData = cdata;
// ...
Tcl_CreateThread(&id, mode_service, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);
In the mode_service function you use the ClientData (which is still NULL) as pointer to a char array:
char* Var = (char *) clientData;
Which is a pointer to the address 0x00.
And then you tell printf to dereference this NULL pointer:
printf("%s\n", Var);
Which obviously crashes your program.
Using the C api with sqlite (v 3.7.13), I'm trying to list all attached databases of the current connection:
sqlite3_stmt* pCompiledSql;
if(SQLITE_OK == sqlite3_prepare_v2(database, "PRAGMA database_list;", -1, &pCompiledSql, nullptr))
{
while(SQLITE_ROW == sqlite3_step(pCompiledSql))
{
const char* pName = reinterpret_cast<const char*>(sqlite3_column_text(pCompiledSql, 1));
const char* pFile = reinterpret_cast<const char*>(sqlite3_column_text(pCompiledSql, 2));
// Using pName and PFile...
}
}
Where database is a handle to an existing database with several databases attached. The same code works fine with statements like "SELECT * FROM testtable;"
However with the pragma call the first step call will just return an SQLITE_DONE straight away.
I'm pretty sure I'm ovelooking something obvious but without much experience with SQLite I'm stuck now... What can possibly go wrong here?
The fourth parameter of sqlite3_prepare_v2 is a pointer to the statement pointer, so it must not be pCompiledSql but &pCompiledSql.
Your compiler should have warned you about this.
Can anybody tell me why the following code doesn't work? I don't get any compiler errors.
short value = 10;
SetProp(hCtl, "value", (short*) value);
The third parameter is typed as a HANDLE, so IMO to meet the explicit contract of the function you should save the property as a HANDLE by allocating a HGLOBAL memory block. However, as noted in the comments below, MSDN states that any value can be specified, and indeed when I try it on Windows 7 using...
SetProp(hWnd, _T("TestProp"), (HANDLE)(10)); // or (HANDLE)(short*)(10)
...
(short)GetProp(hWnd, _T("TestProp"));
... I get back 10 from GetProp. I suspect somewhere between your SetProp and GetProp one of two things happens: (1) the value of hWnd is different -- you're checking a different window or (2) a timing issue -- the property hasn't been set yet or had been removed.
If you wanted to use an HGLOBAL instead to follow the specific types of the function signature, you can follow this example in MSDN.
Even though a HANDLE is just a pointer, it's a specific data type that is allocated by calls into the Windows API. Lots of things have handles: icons, cursors, files, ... Unless the documentation explicitly states otherwise, to use a blob of data such as a short when the function calls for a HANDLE, you need a memory handle (an HGLOBAL).
The sample code linked above copies data as a string, but you can instead set it as another data type:
// TODO: Add error handling
hMem = GlobalAlloc(GPTR, sizeof(short));
lpMem = GlobalLock(hMem);
if (lpMem != NULL)
{
*((short*)lpMem) = 10;
GlobalUnlock(hMem);
}
To read it back, when you GetProp to get the HANDLE you must lock it to read the memory:
// TODO: Add error handling
short val;
hMem = (HGLOBAL)GetProp(hwnd, ...);
if (hMem)
{
lpMem = GlobalLock(hMem);
if (lpMem)
{
val = *((short*)lpMem);
}
}
I would create the short on the heap, so that it continues to exist, or perhaps make it global, which is perhaps what you did. Also the cast for the short address needs to be void *, or HANDLE.