Thanks for that, will have a look at the altered C code, but not sure
yet if I can compile. Just have never done it yet.
As I posted earlier I think I have found the trouble.
Due to a simple typo I enclosed the queries in that table SQL in
double quotes, where it should have been single quotes.
At work now, but will see if I can test in a bit, but I think that is it.
> 1. Use like you have used sqlite_get_table, but for situations when you
> don't need a result set (like Update queries or Pragma commands).
I think this was already in Todd's dll.
RBS
> Hello.
>
> At 14:32 2/2/2007 +0000, you wrote:
>>lReturnedRows is one of the function arguments, so that is fine.
>>
>>I have made some progress though and that is that this problem only
>> occurs
>>with this particular table, called SQL. It is a table that logs all the
>> SQL
>>statements that run in my app. When I instead make this for example
>>sqlite_master there is no problem ever.
>>No idea though why this table would cause a problem. Could it be that
>>one of the items in that table is a reserved word?
>>
>>CREATE TABLE 'SQL'
>>([STATEMENT_COUNT] INTEGER,
>>[DB] TEXT,
>>[QUERY_TIME] TEXT,
>>[QUERY_LENGTH] REAL,
>>[QUERY] TEXT)
>>
>>Any other ideas what could be wrong with this table?
>
> It is possible that the result set is too large to fit in the memory
> constraints you have, so when one of the memory allocations in the
> sqlite_get_table fails, the application crashes.
> Can you run the same statement from the sqlite3 command line application
> and see if it returns the expected results? and if it's very long?
>
> In any case, I've worked a bit on the function, and here's the result:
>
> VBSQL.h ---------------------------------
>
> #include <windows.h>
> #include <stdio.h>
> #include <io.h>
> #include <oleauto.h>
> #include <wtypes.h>
> #include "sqlite3.h"
>
> SAFEARRAY * __stdcall sqlite_get_table(sqlite3 * , const char *, BSTR * ,
> long*, VARIANT);
> BSTR __stdcall sqlite_libversion(void);
> int __stdcall sqlite_exec(sqlite3*, const char*, BSTR*);
>
> VBSQL.c ---------------------------------
> #include "vbsqlite.h"
>
> #define MEMORY_ERROR "Memory allocation error"
>
> BOOL FillVariantFromString(VARIANT* pVariant, const char* pString)
> {
> int nLen;
> LPOLESTR pOLEString;
>
> VariantClear(pVariant);
>
> nLen = MultiByteToWideChar( CP_ACP, 0, pString, -1, NULL, 0);
> if (nLen == 0)
> return FALSE;
> nLen++;
> pOLEString = CoTaskMemAlloc(nLen * sizeof(WCHAR));
> if (pOLEString == NULL)
> return FALSE;
> if (MultiByteToWideChar( CP_ACP, 0, pString, -1, pOLEString,
> nLen)
> == 0)
> {
> CoTaskMemFree(pOLEString);
> return FALSE;
> }
> pVariant->bstrVal = SysAllocString(pOLEString);
> V_VT(pVariant) = VT_BSTR;
> CoTaskMemFree(pOLEString);
> return TRUE;
> }
>
> SAFEARRAY * __stdcall sqlite_get_table(
> sqlite3 *db, /* The database on which the SQL executes */
> const char *zSql, /* The SQL to be executed */
> BSTR *ErrMsg, /* Write error messages here */
> long* pNumberOfRows, /* Number of rows in the returned array (ALWAYS
> without the headers!) */
> VARIANT varIncludeHeaders /* TRUE to include headers, FALSE not to */
> ) /* Return the SAFEARRAY */
> {
> // Temp result fields
> char **pSQL_Results;
> char *pErrMessage= 0;
> int nNumberOfColumns;
> int nResult;
> SAFEARRAY* pResult = NULL;
>
> nResult = sqlite3_get_table(db, zSql, &pSQL_Results,
> pNumberOfRows, &nNumberOfColumns, &pErrMessage);
>
> if (nResult == SQLITE_OK)
> {
> SAFEARRAYBOUND SA_Bounds[2];
>
> sqlite3_free(pErrMessage);
> if (nNumberOfColumns == 0)
> {
> sqlite3_free_table(pSQL_Results);
> // Return an empty array - to make sure nothing
> happens:
> SA_Bounds[0].cElements = 0;
> SA_Bounds[0].lLbound = 0;
> pResult = SafeArrayCreate(VT_VARIANT, 1,
> SA_Bounds);
> if (pResult == NULL)
> {
> *ErrMsg =
> SysAllocStringByteLen(MEMORY_ERROR,strlen(MEMORY_ERROR) );
> return NULL; // Don't know what this will
> do. NEVER USE AN ARRAY when an error was returned!
> }
> }
> else
> {
> //We have a resultset so transform this into a
> SAFEARRAY
> // Create SAFEARRAY
> //SAFEARRAY FAR* resultp = NULL;
> BSTR bstrTemporyStringHolder = NULL;
> VARIANT tmpVariant;
> BSTR bstr1 = NULL;
> HRESULT hr;
> LPOLESTR pTempWideDataHolder = NULL;
> int intCurrentRow ; // Tempory counter for
> looping
> long indices[] = {0,0};
> VariantInit(&tmpVariant);
>
> // Set up array bounds
> SA_Bounds[0].cElements = *pNumberOfRows + 1;
> SA_Bounds[0].lLbound = 0;
> SA_Bounds[1].cElements = nNumberOfColumns;
> SA_Bounds[1].lLbound = 0;
>
> //Create array
> pResult = SafeArrayCreate(VT_VARIANT, 2,
> SA_Bounds);
> if (pResult == NULL)
> {
> *pNumberOfRows = 0;
> sqlite3_free_table(pSQL_Results);
> *ErrMsg =
> SysAllocStringByteLen(MEMORY_ERROR,strlen(MEMORY_ERROR) );
> return NULL; // Don't know what this will
> do. NEVER USE AN ARRAY when an error was returned!
> }
>
> // Put header, if so requested
> if ((varIncludeHeaders.vt != VT_BOOL) ||
> varIncludeHeaders.bVal)
> {
> // Start Place column headers in first
> row
> for (indices[1]=0;
> indices[1]<nNumberOfColumns; indices[1]++)
> {
> if
> (!FillVariantFromString(&tmpVariant, pSQL_Results[indices[1]]))
> {
> *pNumberOfRows = 0;
> SafeArrayDestroy(pResult);
>
> sqlite3_free_table(pSQL_Results);
> *ErrMsg =
> SysAllocStringByteLen(MEMORY_ERROR,strlen(MEMORY_ERROR) );
> return NULL; // Don't
> know
> what this will do. NEVER USE AN ARRAY when an error was returned!
> }
>
> // Safearray Column headers
> hr = SafeArrayPutElement(pResult,
> indices, &tmpVariant);
> if (hr != S_OK)
> {
> *pNumberOfRows = 0;
> SafeArrayDestroy(pResult);
>
> sqlite3_free_table(pSQL_Results);
> *ErrMsg =
> SysAllocStringByteLen(MEMORY_ERROR,strlen(MEMORY_ERROR) );
> return NULL; // Don't
> know
> what this will do. NEVER USE AN ARRAY when an error was returned!
> }
> }
> VariantClear(&tmpVariant);
> }
>
> // Start Loop through array and fill SAFEARRAY
> for (intCurrentRow=1;
> intCurrentRow<=*pNumberOfRows; intCurrentRow++)
> {
> for (indices[1]=0;
> indices[1]<nNumberOfColumns; indices[1]++)
> {
> const char* pString =
> pSQL_Results[(intCurrentRow * nNumberOfColumns) + indices[1]];
> if (pString == NULL)
> continue;
>
> if
> (!FillVariantFromString(&tmpVariant, pSQL_Results[(intCurrentRow *
> nNumberOfColumns) + indices[1]]))
> {
> *pNumberOfRows = 0;
> SafeArrayDestroy(pResult);
>
> sqlite3_free_table(pSQL_Results);
> *ErrMsg =
> SysAllocStringByteLen(MEMORY_ERROR,strlen(MEMORY_ERROR) );
> return NULL; // Don't
> know
> what this will do. NEVER USE AN ARRAY when an error was returned!
> }
> hr = SafeArrayPutElement(pResult,
> indices, &tmpVariant);
> if (hr != S_OK)
> {
> *pNumberOfRows = 0;
> SafeArrayDestroy(pResult);
>
> sqlite3_free_table(pSQL_Results);
> *ErrMsg =
> SysAllocStringByteLen(MEMORY_ERROR,strlen(MEMORY_ERROR) );
> return NULL; // Don't
> know
> what this will do. NEVER USE AN ARRAY when an error was returned!
> }
> }
> }
> VariantClear(&tmpVariant);
> }
> // END Loop through array and fill SAFEARRAY
> sqlite3_free_table(pSQL_Results);
> }
> else
> {
> *pNumberOfRows = 0;
> *ErrMsg = SysAllocStringByteLen(pErrMessage,
> strlen(pErrMessage) );
> sqlite3_free(pErrMessage);
> }
>
> return pResult;
> }
>
> BSTR __stdcall sqlite_libversion()
> {
> return SysAllocStringByteLen(SQLITE_VERSION,
> strlen(SQLITE_VERSION) );
> }
>
> BSTR __stdcall sqlite3_libversion_number()
> {
> return SysAllocStringByteLen(SQLITE_VERSION,
> strlen(SQLITE_VERSION) );
> }
>
> int __stdcall sqlite_exec(
> sqlite3* pDB,
> const char *sql, /* SQL to be executed */
> BSTR *errmsg /* Error msg written here */
> )
> {
> char *pErrMessage = NULL;
> int nResult = sqlite3_exec(pDB, sql, NULL, NULL, &pErrMessage);
>
> if (nResult != SQLITE_OK)
> {
> *errmsg = SysAllocStringByteLen(pErrMessage,
> strlen(pErrMessage) );
> }
>
> sqlite3_free(pErrMessage);
> return nResult;
> }
> ---------------------------
>
> And the VB definitions for sqlite_get_table and sqlite_exec are:
> Private Declare Function sqlite_get_table Lib "SQLite3VB.dll" (ByVal
> DB_Handle As Long, ByVal SQLString As String, ByRef ErrStr As String,
> ByRef
> rows As Long, ByVal bIncludeHeader As Boolean) As Variant()
> Private Declare Function sqlite_exec Lib "SQLite3VB.dll" (ByVal DB_Handle
> As Long, ByVal SQLString As String, ByRef ErrStr As String) As Long
>
> Notes for sqlite_get_table:
> 1. Added rows which will return filled with the number of rows in the
> result (without the headers!)
> 2. Added bIncludeHeader, which, if set to False, will not include the
> column headers in the result
> 3. If you want, you can make it safer by returning a Long (error code),
> and
> sending the array back as one of the variables (like rows). It's safer as
> it won't be used upon error, unlike the current situation
>
> Notes for sqlite_exec:
> 1. Use like you have used sqlite_get_table, but for situations when you
> don't need a result set (like Update queries or Pragma commands).
> 2. The return value is one of the SQLITE_ constants (SQLITE_OK is 0)
>
>
> Guy
>
>
>
> -----------------------------------------------------------------------------
> To unsubscribe, send email to [EMAIL PROTECTED]
> -----------------------------------------------------------------------------
>
>
>
-----------------------------------------------------------------------------
To unsubscribe, send email to [EMAIL PROTECTED]
-----------------------------------------------------------------------------