// dataprovider.cpp
#include "StdAfx.h"
#include "dataprovider.h"
#include "valuework.hpp"
BL_INIT_CONTEXT(SQLiteDataProvider);
const char idParamName[] = "@sqlite_data_provider_id";
const char rowCountParamName[] = "@sqlite_data_provider_rowcount";
const char keyParamPattern[] = "@sqlite_data_provider_key";
const char trimPattern[] = " \t\r\n";
int SQLiteDataRow::GetFieldCount()
{
return m_fCount;
}
int SQLiteDataRow::GetFieldIndexOf(LPCSTR szFieldName)
{
return m_pParent->findField(szFieldName);
}
LPCSTR SQLiteDataRow::GetFieldName(int nIndex)
{
return m_pParent->fieldName(nIndex) ;
}
DataType SQLiteDataRow::GetFieldType(int nIndex)
{
switch(m_pValues[nIndex].type)
{
case typeNumber:
return dtNumeric;
case typeDate:
return dtDate;
default:
return dtText;
}
}
void SQLiteDataRow::FormatField(int nIndex, CString& strValue)
{
CV7DataRow::FormatValue(m_pValues[nIndex], strValue);
}
UINT SQLiteDataRow::GetRowIndex()
{
return 0;
}
const CValue& SQLiteDataRow::GetValue(int nIndex) const
{
return m_pValues[nIndex];
}
SQLiteDataRow::SQLiteDataRow(SQLiteDataProvider* pParent)
{
m_pParent = pParent;
m_fCount = m_pParent->fieldsCount();
m_pValues = (CValue*)new char[sizeof(CValue) * m_fCount];
}
SQLiteDataRow::SQLiteDataRow(DWORD fc)
{
m_pParent = NULL;
m_fCount = fc;
m_pValues = (CValue*)new char[sizeof(CValue) * m_fCount];
for(DWORD i = 0; i < m_fCount; i++)
m_pValues[i].CValue::CValue();
}
SQLiteDataRow::~SQLiteDataRow()
{
CValue* pValue = m_pValues;
for(DWORD c = m_fCount; c--; pValue++)
pValue->CValue::~CValue();
delete [] (char*) m_pValues;
}
void SQLiteDataProvider::QueryRows(CDataRow* pRowFrom, int nRowsCount, int nPageSizeHint)
{
clearRows();
SQLiteQuery* pQuery = getQuery(nRowsCount > 0 ? (pRowFrom ? qDown : qTop) : (pRowFrom ? qUp : qBottom));
bindKeyValues(pQuery, static_cast<SQLiteDataRow*>(pRowFrom));
pQuery->setSqlParam(rowCountParamName, nRowsCount < 0 ? -nRowsCount : nRowsCount, 0);
DataProviderResultLoader executor(this, &m_rows);
executor.execute(pQuery);
}
CDataRow* SQLiteDataProvider::Fetch()
{
if(m_rows.GetSize())
{
CDataRow* pRow = (SQLiteDataRow*)m_rows[0];
m_rows.RemoveAt(0);
return pRow;
}
return NULL;
}
BOOL SQLiteDataProvider::RefreshRow(CDataRow* pRowFrom)
{
if(m_debug)
DoMsgLine(" SQLite: ");
if(!pRowFrom)
return FALSE;
SQLiteDataRow* pRow = static_cast<SQLiteDataRow*>(pRowFrom);
SQLiteQuery* pQuery = getQuery(qCurRow);
bindKeyValues(pQuery, pRow);
RowsArray tempDst;
DataProviderResultLoader executor(this, &tempDst);
executor.execute(pQuery);
if(tempDst.GetSize() != 1)
return FALSE;
SQLiteDataRow* pNewRow = tempDst[0];
CValue* pOldValues = pRow->m_pValues;
pRow->m_pValues = pNewRow->m_pValues;
pNewRow->m_pValues = pOldValues;
pNewRow->m_fCount = pRow->m_fCount;
pRow->m_fCount = fieldsCount();
delete pNewRow;
return TRUE;
}
BOOL SQLiteDataProvider::CompareRows(CDataRow* pRow1, CDataRow* pRow2) const
{
CValue *pVals1 = static_cast<SQLiteDataRow*>(pRow1)->m_pValues,
*pVals2 = static_cast<SQLiteDataRow*>(pRow2)->m_pValues;
for(DWORD idx = 0, midx = keyFieldsCount(); idx < midx ; idx++)
{
if(pVals1[idx] != pVals2[idx])
return FALSE;
}
return TRUE;
}
BOOL SQLiteDataProvider::GetRowCount(UINT* pCount)
{
return FALSE;
}
DataType SQLiteDataProvider::GetQuickSearchType(LPCSTR szFieldName)
{
field_info* pFI;
if(m_fieldByName.Lookup(szFieldName, pFI) && 0 != (pFI->flags & field_info::qsPossible))
return dtText;
return dtUndefined;//dtText;
}
void SQLiteDataProvider::QuickSearch(stQuickSearchPattern& QSPattern)
{
field_info* pFI;
if(QSPattern.dataType != dtText || !m_fieldByName.Lookup(QSPattern.szFieldName, pFI)
|| 0 == (pFI->flags & field_info::qsPossible) || QSPattern.pTextData->IsEmpty())
{
QSPattern.pTextData->Empty();
return;
}
SQLiteQuery* pQuery = m_queries[qQuickSearch];
if(!pQuery)
pQuery = m_queries[qQuickSearch] = m_pDataBase->newQuery();
if(m_lastQSColumn != pFI)
{
m_QSColumn = -1;
CString strSqlText("select\r\n"), strOrder(" order by\r\n");
field_info* pFields = m_fieldsInfo;
for(DWORD idx = 0; idx < keyFieldsCount(); idx++, pFields++)
{
strSqlText += pFields->expression + pFields->alias + ",\r\n";
strOrder += pFields->expression + ",\r\n";
if(pFields == pFI)
m_QSColumn = idx;
}
if(-1 == m_QSColumn)
{
strSqlText += pFI->expression + pFI->alias;
m_QSColumn = idx;
}
else
strSqlText.GetBufferSetLength(strSqlText.GetLength() - 3);
strSqlText += m_from;
if(!m_where.IsEmpty())
strSqlText = strSqlText + " where\r\n" + m_where + "\r\n";
strOrder.GetBufferSetLength(strOrder.GetLength() - 3);
strSqlText += strOrder;
pQuery->setDebug(m_debug);
pQuery->prepare(strSqlText);
m_lastQSColumn = pFI;
}
m_sqlParams.applyParamsToQuery(pQuery, -1);
SQLiteDataRow qsRow(keyFieldsCount());
QuickSearchResultLoader qsloader(*QSPattern.pTextData, qsRow.m_pValues, keyFieldsCount(), m_QSColumn);
int maxSymb = qsloader.find(pQuery);
QSPattern.pTextData->GetBufferSetLength(maxSymb);
if(maxSymb)
SetCurrentRow(&qsRow);
}
void SQLiteDataProvider::OnAttach()
{
ResetData();
}
CV7DataRow* SQLiteDataProvider::GetV7DataRow(CDataRow* pDataRow) const
{
return static_cast<SQLiteDataRow*>(pDataRow);
}
void SQLiteDataProvider::GetRowValue(CDataRow* pDataRow, CValue& value) const
{
if(idFieldPos() >= 0)
value = static_cast<SQLiteDataRow*>(pDataRow)->m_pValues[idFieldPos()];
else
value.Reset();
}
int modificatorByType(typesOfFields t)
{
switch(t)
{
case ttReference:
case ttDocument:
case ttEnum:
case ttAccount:
case ttCalendar:
return 1;
case ttUndefine:
return -1;
break;
}
return 0;
}
CDataRow* SQLiteDataProvider::BuildRowByValue(const CValue& value)
{
if(idFieldPos() < 0)
return NULL;
SQLiteQuery* pQuery = getQuery(qID);
pQuery->setSqlParam(idParamName, value, modificatorByType(fieldInfo(idFieldPos()).type));
RowsArray tempDst;
DataProviderResultLoader executor(this, &tempDst);
executor.execute(pQuery);
if(tempDst.GetSize() != 1)
return NULL;
return (SQLiteDataRow*)tempDst[0];
}
SQLiteDataProvider::SQLiteDataProvider()
{
m_pDataBase = NULL;
m_fieldsInfo = NULL;
m_fieldsInfoCount = 0;
memset(m_queries, 0, sizeof(m_queries));
m_debug = FALSE;
m_lastQSColumn = NULL;
m_queryFieldsNames = NULL;
m_keyParamNames = NULL;
}
BOOL SQLiteDataProvider::SetDataBase(CValue** ppParams)
{
clearAll();
if(ppParams[0]->IsEmpty())
{
m_pDataBase = new CSLDataBase;
m_pDataBase->open(":memory:");
}
else
{
if(ppParams[0]->type != 100 || !safeDynCast(ppParams[0]->m_Context, m_pDataBase))
CBLModule::RaiseExtRuntimeError(" SQLite", FALSE);
m_pDataBase->m_RefCount++;
}
ResetData();
return TRUE;
}
void removeComments(CString& strQuery)
{
enum {sNone, sQuote, sLiteral, sMinus, sDiv, sRemark, sMultRem, sMultRemMult};
DWORD state = sNone;
LPSTR pWrite = strQuery.GetBufferSetLength(strQuery.GetLength());
LPCSTR pRead = pWrite, pStart = pRead;
for(;; pRead++)
{
DWORD s = (DWORD)(BYTE)*pRead;
switch(state)
{
case sNone:
if('\'' == s)
state = sQuote;
else if('[' == s)
state = sLiteral;
else if('-' == s)
{
state = sMinus;
continue; //
}
else if('/' == s)
{
state = sDiv;
continue; //
}
break;
case sQuote: // ' '
if('\'' == s)
state = sNone;
break;
case sLiteral:
if(']' == s)
state = sNone;
break;
case sMinus: // '-'
if('-' == s)
{
state = sRemark;
continue;
}
// ,
*pWrite++ = '-';
if('/' == s)
{
state = sDiv;
continue;
}
state = sNone;
break;
case sDiv: // '/'
if('*' == s)
{
state = sMultRem;
continue;
}
*pWrite++ = '/';
if('-' == s)
{
state = sMinus;
continue;
}
state = sNone;
break;
case sRemark: // '--'
if('\r' != s && 0 != s)
continue;
*pWrite++ = ' '; // , \r
state = sNone;
break;
case sMultRem: // '/*'
if(0 != s)
{
if('*' == s)
state = sMultRemMult;
continue;
}
break;
case sMultRemMult: // '/* *'
if(0 != s)
{
if('/' == s)
{
state = sNone;
*pWrite++ = ' ';
}
else if('*' != s)
state = sMultRem;
continue;
}
break;
}
if(!s)
break;
if(pRead > pWrite)
*pWrite = s;
pWrite++;
}
if(pRead > pWrite + 1) //
strQuery.GetBufferSetLength(pWrite - pStart);
strQuery.TrimLeft(trimPattern);
}
inline BOOL isWordSymbol(DWORD s)
{
return (s >= 'A' && s <='Z') || (s >= 'a' && s <='z') || s > 0x80 || s == '_' || (s >= '0' && s <= '9');
}
void splitQuery(CString& strQuery, CStringArray& fields, CString& strFrom, CString& strWhere)
{
removeComments(strQuery);
LPCSTR ptr = strQuery;
ptr += sizeof("select") - 1;
//
// , from
DWORD parentheses = 0, inLiterals = 0;
LPCSTR pStartOfField = ptr, pStartOfFrom = NULL;
LPCSTR keyword = "from";
for(;;)
{
DWORD s = (DWORD)(BYTE)*ptr++;
if(!s)
break;
if(inLiterals)
{
if( (1 == inLiterals && '\'' == s) ||
(2 == inLiterals && ']' == s))
inLiterals = 0;
}
else if('\'' == s)
inLiterals = 1;
else if('[' == s)
inLiterals = 2;
else if('(' == s)
parentheses++;
else if(')' == s)
parentheses--;
else if(0 == parentheses)
{
if(!pStartOfFrom && ',' == s)
{
fields.Add(CString(pStartOfField, ptr - pStartOfField - 1));
pStartOfField = ptr;
}
else
{
//
LPCSTR pKeyword = keyword;
DWORD k;
for(;;)
{
k = (DWORD)(BYTE)*pKeyword++;
if(k != (s | 0x20) || !s)
break;
s = (DWORD)(BYTE)*ptr++;
}
if(isWordSymbol(s))
{
do
{
s = (DWORD)(BYTE)*ptr++;
}while(isWordSymbol(s));
ptr--;
}
else if(0 == k)
{
if(!pStartOfFrom)
{
pStartOfFrom = ptr - 1;
keyword = "where";
fields.Add(CString(pStartOfField, ptr - pStartOfField - sizeof("from")));
}
else
{
DWORD fromLen = ptr - pStartOfFrom - sizeof("where");
memcpy(strFrom.GetBufferSetLength(fromLen), pStartOfFrom, fromLen);
strWhere = ptr - 1;
return;
}
}
}
}
}
strFrom = pStartOfFrom;
}
BOOL SQLiteDataProvider::SetQueryText(CValue** ppParams)
{
if(!m_pDataBase)
CBLModule::RaiseExtRuntimeError(" ", FALSE);
CString strQueryText = ppParams[0]->GetString();
CString strKeyField = ppParams[1]->GetString();
CString strIDField = ppParams[2]->GetString();
if(strKeyField.IsEmpty())
CBLModule::RaiseExtRuntimeError(" ", FALSE);
CStringArray fieldNames;
CArray<typesOfFields, typesOfFields> types;
DWORD fieldsCount;
// ,
{
auto_ptr<SQLiteQuery> qTest(m_pDataBase->newQuery());
m_metaParser.processSql(strQueryText);
qTest->prepare(strQueryText);
//
qTest->getFields(fieldNames, types);
fieldsCount = fieldNames.GetSize();
if(!fieldsCount)
CBLModule::RaiseExtRuntimeError(" ", FALSE);
}
// .
CDWordArray newKeyFields;
int newIDField = -1;
{
CStringArray strKeyFields;
SplitStr2Array(strKeyField, strKeyFields, ',');
CNoCaseMap<int> namesToPos;
for(DWORD idx = 0; idx < fieldsCount; idx++)
namesToPos[fieldNames[idx]] = idx;
for(idx = 0; idx < strKeyFields.GetSize(); idx++)
{
CString keyName = strKeyFields[idx];
keyName.TrimLeft(trimPattern);
keyName.TrimRight(trimPattern);
SQLiteQuery::typeField(keyName);
int pos;
if(!namesToPos.Lookup(keyName, pos))
{
CString msg;
msg.Format(" '%s' ", keyName);
CBLModule::RaiseExtRuntimeError(msg, FALSE);
}
for(DWORD k = 0; k < newKeyFields.GetSize(); k++)
{
if(newKeyFields[k] == pos)
{
CString msg;
msg.Format(" '%s' ", keyName);
CBLModule::RaiseExtRuntimeError(msg, FALSE);
}
}
newKeyFields.Add(pos);
}
if(!newKeyFields.GetSize())
CBLModule::RaiseExtRuntimeError(" ", FALSE);
if(!strIDField.IsEmpty())
{
strIDField.TrimLeft(trimPattern);
strIDField.TrimRight(trimPattern);
SQLiteQuery::typeField(strIDField);
if(!namesToPos.Lookup(strIDField, newIDField))
{
CString msg;
msg.Format(" '%s' ", strIDField);
CBLModule::RaiseExtRuntimeError(msg, FALSE);
}
}
}
// ,
CStringArray fieldsExpressions, fieldAliases;
CString from, where;
splitQuery(strQueryText, fieldsExpressions, from, where);
//
for(DWORD idx = 0, midx = fieldsExpressions.GetSize(); idx < midx; idx++)
{
CString expr = fieldsExpressions[idx], alias;
expr.TrimLeft(trimPattern);
expr.TrimRight(trimPattern);
LPCSTR start = expr, ptr = start + expr.GetLength() - 1;
if(*ptr == ']')
{
while(*--ptr != '[');
LPCSTR pAs = --ptr;
while(pAs > start + 2 && (*pAs == ' ' || *pAs == '\t' || *pAs == '\r' || *pAs == '\n'))
pAs--;
if(pAs[0] | 0x20 == 's' && pAs[-1] | 0x20 == 'a' &&
(pAs[-2] == ' ' || pAs[-2] == '\t' || pAs[-2] == '\n'))
ptr = pAs - 1;
alias = ptr;
expr.GetBufferSetLength(ptr - start);
}
fieldsExpressions[idx] = expr;
fieldAliases.Add(alias);
}
m_metaParser.reset();
CNoCaseMap<int> usedFields;
if(m_fieldsInfo)
{
for(DWORD idx = 0; idx < fieldsInfoCount(); idx++)
{
if(0 != (m_fieldsInfo[idx].flags & field_info::inUse))
usedFields[m_fieldsInfo[idx].nameOfQueryColumn] = 0;
}
}
clearQueriesData();
// fieldsInfo
m_fieldsInfoCount = fieldsCount;
m_fieldsInfo = new field_info[fieldsCount];
field_info* pFI = m_fieldsInfo;
// :
// , -,
// . ,
// .
//
m_keyFieldCount = newKeyFields.GetSize();
m_keyParamNames = new CString[m_keyFieldCount];
int nIDFieldAdded = -1;
for(idx = 0; idx < m_keyFieldCount; idx++)
{
DWORD pos = newKeyFields[idx];
pFI->type = types[pos];
pFI->expression = fieldsExpressions[pos];
pFI->alias = fieldAliases[pos];
pFI->nameOfQueryColumn = fieldNames[pos];
pFI->flags = field_info::keyField | field_info::inUse;
m_fieldByName[pFI->nameOfQueryColumn] = pFI;
fieldsExpressions[pos].Empty();
m_keyParamNames[idx].Format("%s%i", keyParamPattern, idx); // SQL-
pFI++;
if(newIDField == pos)
nIDFieldAdded = idx;
}
// -,
if(newIDField >= 0 && nIDFieldAdded < 0)
{
pFI->type = types[newIDField];
pFI->expression = fieldsExpressions[newIDField];
pFI->alias = fieldAliases[newIDField];
pFI->nameOfQueryColumn = fieldNames[newIDField];
pFI->flags = field_info::idField | field_info::inUse;
m_fieldByName[pFI->nameOfQueryColumn] = pFI;
fieldsExpressions[newIDField].Empty();
pFI++;
nIDFieldAdded = idx;
}
//
for(idx = 0; idx < fieldsCount ; idx++)
{
if(!fieldsExpressions[idx].IsEmpty())
{
pFI->type = types[idx];
pFI->expression = fieldsExpressions[idx];
pFI->alias = fieldAliases[idx];
pFI->nameOfQueryColumn = fieldNames[idx];
pFI->flags = 0;
m_fieldByName[pFI->nameOfQueryColumn] = pFI;
pFI++;
}
}
m_idFieldPos = nIDFieldAdded;
from.TrimLeft(trimPattern);
from.TrimRight(trimPattern);
where.TrimLeft(trimPattern);
where.TrimRight(trimPattern);
m_from.Format("\r\n from\r\n%s\r\n ", from);
if(!where.IsEmpty())
m_where.Format("(%s)", where);
if(usedFields.GetCount())
{
for(DWORD idx = 0; idx < fieldsInfoCount(); idx++)
{
int i;
if(usedFields.Lookup(m_fieldsInfo[idx].nameOfQueryColumn, i))
m_fieldsInfo[idx].flags |= field_info::inUse;
}
}
ResetData();
return TRUE;
}
void SQLiteDataProvider::clearRows()
{
// , ,
SQLiteDataRow** ppRows = (SQLiteDataRow**)m_rows.GetData();
for(DWORD c = m_rows.GetSize(); c--; )
delete *ppRows++;
m_rows.RemoveAll();
}
void SQLiteDataProvider::clearQueriesData()
{
clearRows();
for(DWORD idx = 0; idx < qLast; idx++)
{
delete m_queries[idx];
m_queries[idx] = 0;
}
m_sqlParams.dirtyQueries = 0xFFFFFFFF;
m_keyFieldCount = 0;
m_countOfColumns = 0;
delete [] m_queryFieldsNames; //
m_queryFieldsNames = NULL;
delete [] m_keyParamNames;
m_keyParamNames = NULL;
m_idFieldPos = -1; // -
m_fieldByName.RemoveAll();
m_select.Empty();
m_from.Empty();
m_where.Empty();
m_lastQSColumn = NULL;
delete [] m_fieldsInfo; //
m_fieldsInfoCount = 0;
}
void SQLiteDataProvider::clearAll()
{
clearQueriesData();
if(m_pDataBase)
{
m_pDataBase->DecrRef();
m_pDataBase = NULL;
}
}
SQLiteQuery* SQLiteDataProvider::getQuery(qTypes type)
{
SQLiteQuery* pQuery = m_queries[type];
if(!pQuery)
{
auto_ptr<SQLiteQuery> query(m_pDataBase->newQuery());
query->setDebug(m_debug);
if(m_debug)
{
static const LPCSTR names[] = {" ", " ", " ",
" ", " id", " "};
DoMsgLine(" SQLite: '%s'", mmNone, names[type]);
}
//
if(m_select.IsEmpty()) //
{
DWORD countOfFieldsInQuery = 0;
for(DWORD idx = 0; idx < fieldsInfoCount(); idx++)
{
if(fieldInfo(idx).flags & field_info::inUse)
countOfFieldsInQuery++;
}
if(countOfFieldsInQuery != m_countOfColumns)
{
m_countOfColumns = countOfFieldsInQuery;
delete [] m_queryFieldsNames;
m_queryFieldsNames = new LPCSTR[m_countOfColumns];
}
m_select = "select\r\n";
DWORD pos = 0;
for(idx = 0; idx < fieldsInfoCount(); idx++)
{
const field_info& fi = fieldInfo(idx);
if(fi.flags & field_info::inUse)
{
m_select += fi.expression + fi.alias + ",\r\n";
m_fieldsInfo[idx].posInQuery = pos;
m_queryFieldsNames[pos] = fi.nameOfQueryColumn;
pos++;
}
else
m_fieldsInfo[idx].posInQuery = -1;
}
m_select.GetBufferSetLength(m_select.GetLength() - 3);
}
CString mainSqlQuery(m_select + m_from), strSql;
if(qDown == type || qUp == type)
{
for(DWORD k = keyFieldsCount(); ;)
{
k--;
strSql += mainSqlQuery + " where\r\n";
if(!m_where.IsEmpty())
strSql += m_where + "\r\n and \r\n";
for(DWORD i = 0; i < k ; i++)
strSql += fieldInfo(i).expression + " = " + keySQLParamName(i) + " and\r\n";
strSql += fieldInfo(k).expression + (qDown == type ? " > " : " < ") + keySQLParamName(k);
if(k)
strSql += "\r\n union all \r\n";
else
break;
}
}
else
{
strSql = mainSqlQuery;
if(qID == type)
{
strSql += " where\r\n";
if(!m_where.IsEmpty())
strSql += m_where + "\r\n and \r\n";
strSql += fieldInfo(idFieldPos()).expression + " = " + idParamName;
}
else if(qCurRow == type)
{
strSql += " where\r\n";
if(!m_where.IsEmpty())
strSql += m_where + "\r\n and \r\n";
for(DWORD idx = 0, midx = keyFieldsCount() -1 ; idx < midx ; idx++)
strSql += fieldInfo(idx).expression + " = " + keySQLParamName(idx) + " and\r\n";
strSql += fieldInfo(idx).expression + " = " + keySQLParamName(idx);
}
else
{
if(!m_where.IsEmpty())
strSql = strSql + " where\r\n" + m_where;
}
}
if(qID != type && qCurRow != type)
{
strSql += "\r\n order by \r\n";
CString direction(qUp == type || qBottom == type ? " desc" : " asc");
for(DWORD idx = 0, midx = keyFieldsCount(); idx < midx ; idx++)
{
strSql += fieldInfo(idx).expression + direction;
if(idx < midx - 1)
strSql += ",\r\n";
}
strSql = strSql + "\r\n limit " + rowCountParamName;
}
else
strSql = strSql + "\r\n limit 1";
query->prepare(strSql);
pQuery = m_queries[type] = query.release();
}
m_sqlParams.applyParamsToQuery(pQuery, type);
return pQuery;
}
void SQLiteDataProvider::bindKeyValues(SQLiteQuery* pQuery, SQLiteDataRow* pRow)
{
if(!pRow)
return;
for(DWORD idx = 0, midx = keyFieldsCount(); idx < midx ; idx++)
{
pQuery->setSqlParam(CValue(keySQLParamName(idx)),
pRow->m_pValues[idx], modificatorByType(fieldInfo(idx).type));
}
}
void SQLiteDataProvider::QueryField(LPCSTR szFieldName)
{
field_info* pFI;
if(m_fieldByName.Lookup(szFieldName, pFI))
{
if(0 == (pFI->flags & field_info::inUse))
{
pFI->flags |= field_info::inUse;
setColumnsChanged();
}
}
}
void SQLiteDataProvider::ReleaseField(LPCSTR szFieldName)
{
field_info* pFI;
if(m_fieldByName.Lookup(szFieldName, pFI))
{
if(0 != (pFI->flags & (field_info::keyField | field_info::idField | field_info::NoAutoDelete)))
return;
if(0 != (pFI->flags & field_info::inUse))
{
pFI->flags &= ~field_info::inUse;
setColumnsChanged();
}
}
}
void SQLiteDataProvider::setFlagOnFields(const CString& strFields, int flag)
{
CString notFound;
CStringArray fields;
SplitStr2Array(strFields, fields, ',');
DWORD dNotFound = 0;
for(DWORD idx = 0, midx = fields.GetSize(); idx < midx; idx++)
{
CString strField = fields[idx];
strField.TrimLeft(trimPattern);
strField.TrimRight(trimPattern);
field_info* pFI;
if(m_fieldByName.Lookup(strField, pFI))
pFI->flags |= flag;
else
{
dNotFound++;
notFound += strField + ',';
}
}
if(dNotFound)
{
notFound.GetBufferSetLength(notFound.GetLength() - 1);
CString msg;
msg.Format(dNotFound == 1 ? " %s " : " %s ", notFound);
CBLModule::RaiseExtRuntimeError(msg, FALSE);
}
}
void SQLiteDataProvider::setColumnsChanged()
{
if(m_select.IsEmpty())
return;
m_select.Empty();
for(DWORD idx = 0; idx < qLast; idx++)
{
delete m_queries[idx];
m_queries[idx] = NULL;
}
m_sqlParams.dirtyQueries = 0xFFFFFFFF;
OnFieldsChanged();
}
BOOL SQLiteDataProvider::GetQueryText(CValue& retVal, CValue** ppParams)
{
BOOL bAll = ppParams[0]->GetNumeric() != 0;
CString text;
if(fieldsInfoCount())
{
text = "select\r\n";
for(DWORD idx = 0; idx < fieldsInfoCount(); idx++)
{
const field_info& fi = fieldInfo(idx);
if(bAll || 0 != (fi.flags & field_info::inUse))
text += fi.expression + fi.alias + ",\r\n";
}
text.GetBufferSetLength(text.GetLength() - 3);
text += m_from;
if(!m_where.IsEmpty())
text = text + " where\r\n" + m_where;
}
retVal = text;
return TRUE;
}
void DataProviderResultLoader::addValues(CValue** ppValues)
{
SQLiteDataRow* pRow = new SQLiteDataRow(m_pProvider);
CValue* pValDst = pRow->m_pValues;
for(DWORD c = m_count; c--; pValDst++, ppValues++)
{
pValDst->CValue::CValue(**ppValues);
pValDst->m_length = (*ppValues)->m_length;
pValDst->m_prec = (*ppValues)->m_prec;
}
m_pDestination->Add(pRow);
}
void QuickSearchResultLoader::addValues(CValue** ppValues)
{
CString str = ppValues[m_testField]->Format();
if(ppValues[m_testField]->type == typeNumber)
str.TrimLeft();
DWORD len = 0;
for(LPCSTR p1 = m_pattern, p2 = str, pStart = p1;;)
{
DWORD s1 = CNoCaseMapBase::m_lotable[ncm_symb::symbol(p1)];
DWORD s2 = CNoCaseMapBase::m_lotable[ncm_symb::symbol(p2)];
if(s1 != s2 || !s1)
break;
p1++;
p2++;
len++;
}
if(len > m_maxSymbols)
{
m_maxSymbols = len;
for(DWORD i = 0; i < m_keysCount; i++)
m_pBestKey[i] = *ppValues[i];
if(len == m_pattern.GetLength())
throw 1;
}
}