// database.h
#pragma once
#include "utex.h"
#include "metaparser.h"
class SQLiteQuery;
class SQLiteBase
{
public:
SQLiteBase() : m_pDataBase(NULL) {}
virtual ~SQLiteBase() { close(); }
sqlite3* base() const { return m_pDataBase; }
void open(const CString& fileName);
void close()
{
if(m_pDataBase)
{
sqlite3_close(m_pDataBase);
m_pDataBase = NULL;
}
}
SQLiteQuery* newQuery();
void traceOn();
const CString& traceResult() const { return m_trace; }
void putVT(CValueTable* pTable, const CString& tableName, BOOL bAsPersistent);
void putObjects(CValue* pObjects, const CString& tableName, BOOL bAsPersistent, const CString& hierarchy);
void setQueryTimeout(int tm)
{
sqlite3_busy_timeout(m_pDataBase, tm);
}
void enableLoadExtension(BOOL bOn)
{
sqlite3_enable_load_extension(m_pDataBase, bOn);
}
protected:
void raiseDBError()
{
CString err(m_pDataBase ? u8text::fromUtf8(sqlite3_errmsg(m_pDataBase)) : " ");
CBLModule::RaiseExtRuntimeError(err, FALSE);
}
friend SQLiteQuery;
static int xCreate(sqlite3*, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char**);
static int xBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info*);
static int xDestroy(sqlite3_vtab *pVTab);
static int xOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
static int xClose(sqlite3_vtab_cursor*);
static int xFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, int argc, sqlite3_value **argv);
static int xNext(sqlite3_vtab_cursor*);
static int xEof(sqlite3_vtab_cursor*);
static int xColumn(sqlite3_vtab_cursor*, sqlite3_context*, int);
static int xRowid(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid);
sqlite3* m_pDataBase;
static CString m_trace;
};
enum typesOfFields
{
ttAsIs,
ttString,
ttDate,
ttNumber,
ttReference,
ttReferenceOne,
ttDocument,
ttDocumentWithLink,
ttDocumentOne,
ttDocKind,
ttDocPresent,
ttEnum,
ttEnumOne,
ttAccount,
ttAccountOne,
ttUndefine,
ttCalcKind,
ttCalendar,
ttSubconto,
ttTime,
ttKindName,
ttKindPresent,
ttSubcKind,
ttSubcPresent,
ttError,
};
typedef CArray<typesOfFields, typesOfFields> TFArray;
class SQLiteQuery
{
public:
virtual ~SQLiteQuery() { close(); }
SQLiteBase* parent() const { return m_pParent; }
void prepare(const CString& query);
void execute(CValue* pDst, CValue* pDstParam, CValue& retVal);
void setSqlParam(const CValue& param, const CValue& value, int mod, BOOL bThrow = TRUE);
void setTextParam(const CString& name, const CValue* pValue)
{
m_parser.setTextParam(name, pValue);
}
void close();
void parseSqlText(CString& query)
{
m_parser.processSql(query);
}
void setDebug(BOOL bDebug)
{
m_bIsDebug = bDebug;
}
BOOL isPrepared() const { return m_pStmt != NULL; }
BOOL needTransaction() const { return m_bNeedTransaction; }
void setNeedTransaction(BOOL bNT) { m_bNeedTransaction = bNT; }
void getFields(CStringArray& fields, TFArray& types);
static void typeField(CString& name, CString* pType = NULL);
protected:
friend SQLiteBase;
SQLiteQuery(SQLiteBase* pBase)
: m_pParent(pBase), m_pStmt(NULL), m_bIsDebug(FALSE), m_columns(NULL), m_bNeedTransaction(FALSE)
{
}
struct column_info
{
column_info(const CString& colName, DWORD col, column_info*& pNext);
void toValue(sqlite3_stmt* pStmt, CValue* pValue);
CString name;
DWORD column;
CType typeForVTColumn;
typesOfFields type;
column_info* linkedField;
column_info* next;
} *m_columns;
sqlite3_stmt* m_pStmt;
SQLiteBase* m_pParent;
MetaParser m_parser;
BOOL m_bIsDebug;
BOOL m_bNeedTransaction;
};
inline SQLiteQuery* SQLiteBase::newQuery() { return new SQLiteQuery(this); }
class CSLDataBase : public CContextImpl<CSLDataBase>, public SQLiteBase
{
public:
BL_BEGIN_CONTEXT("SQLiteBase", "SQLiteBase");
BL_PROC(Open, "", 1) { open(ppParams[0]->GetString()); return TRUE;}
BL_FUNC(IsOpen, "", 0) { retVal = base() != NULL; return TRUE; }
BL_FUNC(BaseHandle, "", 0) { retVal = (long)m_pDataBase; return TRUE; }
BL_PROC(DoProfile, "", 0) { traceOn(); return TRUE; }
BL_FUNC(Profile, "", 0) { retVal = m_trace; m_trace.Empty(); return TRUE; }
BL_PROC(Close, "", 0)
{
for(POSITION pos = m_querys.GetHeadPosition(); pos;)
{
CSLQuery* ptr = m_querys.GetNext(pos);
ptr->close();
}
close();
return TRUE;
}
BL_FUNC(NewQuery, "", 0)
{
CSLQuery* pQuery = new CSLQuery(this);
retVal.AssignContext(pQuery);
pQuery->DecrRef();
return TRUE;
}
BL_PROC_WITH_DEFVAL(PutVT, "", 3);
BL_DEFVAL_FOR(PutVT)
{
if(2 == nParam)
{
if(pValue)
*pValue = 0L;
return TRUE;
}
return FALSE;
}
BL_PROC_WITH_DEFVAL(PutObjects, "", 4)
{
putObjects(ppParams[0], ppParams[1]->GetString(), 0 != (long)ppParams[2]->GetNumeric(), ppParams[3]->GetString());
return TRUE;
}
BL_DEFVAL_FOR(PutObjects)
{
if(nParam == 3)
{
if(pValue)
pValue->Reset();
return TRUE;
}
else if(nParam == 2)
{
if(pValue)
*pValue = 0L;
return TRUE;
}
return FALSE;
}
BL_PROC(SetQueryTimeout, "", 1)
{
setQueryTimeout(ppParams[0]->GetNumeric());
return TRUE;
}
BL_FUNC(FromUTF8, "8", 1)
{
retVal.Reset();
retVal.type = 2;
u8text::fromUtf8(ppParams[0]->GetString(), retVal.m_String);
return TRUE;
}
BL_PROC(EnableLoadExtension, "", 1)
{
enableLoadExtension(ppParams[0]->GetNumeric());
return TRUE;
}
BL_END_CONTEXT();
private:
class CSLQuery : public CContextImpl<CSLQuery, no_init_done, FALSE>, public SQLiteQuery
{
public:
CSLQuery(CSLDataBase* parent) : SQLiteQuery(parent)
{
parent->IncrRef();
m_posInParentList = parent->m_querys.AddTail(this);
}
~CSLQuery()
{
static_cast<CSLDataBase*>(m_pParent)->m_querys.RemoveAt(m_posInParentList);
static_cast<CSLDataBase*>(m_pParent)->DecrRef();
}
BL_BEGIN_CONTEXT("SQLiteQuery", "SQLiteQuery");
BL_FUNC_WITH_DEFVAL(ExecuteQuery, "", 3)
{
prepare(ppParams[0]->GetString());
execute(ppParams[1], ppParams[2], retVal);
close();
return TRUE;
}
BL_DEFVAL_FOR(ExecuteQuery)
{
if(nParam > 0)
{
if(pValue)
pValue->Reset();
return TRUE;
}
return FALSE;
}
BL_PROC(Prepare, "", 1)
{
prepare(ppParams[0]->GetString());
return TRUE;
}
BL_PROC_WITH_DEFVAL(SetParam, "", 3)
{
setSqlParam(*ppParams[0], *ppParams[1], ppParams[2]->GetNumeric());
return TRUE;
}
BL_DEFVAL_FOR(SetParam)
{
if(2 == nParam)
{
if(pValue)
pValue = 0L;
return TRUE;
}
return FALSE;
}
BL_PROC(Substitute, "", 2)
{
setTextParam(ppParams[0]->GetString(), ppParams[1]);
return TRUE;
}
BL_FUNC_WITH_DEFVAL(Exec, "", 2)
{
execute(ppParams[0], ppParams[1], retVal);
return TRUE;
}
BL_DEFVAL_FOR(Exec)
{
if(pValue)
pValue->Reset();
return TRUE;
}
BL_PROC_WITH_DEFVAL(Debug, "", 1)
{
setDebug((long)ppParams[0]->GetNumeric() != 0);
return TRUE;
}
BL_DEFVAL_FOR(Debug)
{
if(pValue)
*pValue = 1;
return TRUE;
}
BL_FUNC(ParseSqlText, "", 1)
{
CString text = ppParams[0]->GetString();
parseSqlText(text);
retVal = text;
return TRUE;
}
BL_PROP_RW(NeedTransaction, "")
{
value = needTransaction();
return TRUE;
}
BL_PROP_WRITE(NeedTransaction)
{
setNeedTransaction(0 != (long)value.GetNumeric());
return TRUE;
}
BL_END_CONTEXT();
POSITION m_posInParentList;
};
friend CSLQuery;
CList<CSLQuery*, CSLQuery*> m_querys;
};