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]
-----------------------------------------------------------------------------

Reply via email to