//-< QUERY.H >-------------------------------------------------------*--------*
// FastDB Version 1.0 (c) 1999 GARRET * ? *
// (Main Memory Database Management System) * /\| *
// * / \ *
// Created: 20-Nov-98 K.A. Knizhnik * / [] \ *
// Last update: 10-Dec-98 K.A. Knizhnik * GARRET *
//-------------------------------------------------------------------*--------*
// Constructing and hashing database query statements
//-------------------------------------------------------------------*--------*
#ifndef __QUERY_H__
#define __QUERY_H__
/**
* Element of the query
*/
class FASTDB_DLL_ENTRY dbQueryElement {
friend class dbQuery;
friend class dbCompiler;
friend class dbQueryExpression;
friend class dbQueryElementAllocator;
friend class dbCLI;
public:
enum ElementType {
qExpression, // part of SQL expression
qVarBool,
qVarInt1,
qVarInt2,
qVarInt4,
qVarInt8,
qVarReal4,
qVarReal8,
qVarString,
qVarStringPtr,
qVarReference,
qVarArrayOfRef,
qVarArrayOfRefPtr,
qVarRawData
#ifdef USE_STD_STRING
,qVarStdString
#endif
};
ElementType getType() const { return type; }
dbQueryElement* nextElement() const { return next; }
void* operator new (size_t size EXTRA_DEBUG_NEW_PARAMS);
void operator delete(void* p EXTRA_DEBUG_NEW_PARAMS);
char* dump(char* buf);
char* dumpValues(char* buf);
dbQueryElement(ElementType t, void const* p,
dbTableDescriptor* table = NULL)
{
type = t;
ptr = p;
ref = table;
next = NULL;
}
private:
dbQueryElement* next;
void const* ptr;
ElementType type;
dbTableDescriptor* ref;
};
/**
* Allocator of query elements. This class links deallocated elements in the list of free elements,
* and reused them in future. So number of system memory allocator invocations is dramatically reduced.
* Cleanup of free elements lst is performed by dbDatabase::cleanup() method
*/
class FASTDB_DLL_ENTRY dbQueryElementAllocator {
friend class dbDatabase;
dbMutex& mutex;
dbQueryElement* freeChain;
public:
void deallocate(dbQueryElement* first, dbQueryElement** lastNext) {
dbCriticalSection cs(mutex);
if (first != NULL) {
*lastNext = freeChain;
freeChain = first;
}
}
void* allocate(size_t size);
dbQueryElementAllocator();
~dbQueryElementAllocator();
static dbQueryElementAllocator instance;
};
/**
* This class represents component of the structure.
* It is mostly needed for implementation of application specific database types. For example, look at
* dbDate class. It contains int4 jday component which stores time in seconds sinse 1970.
* This class defines its own comparison methods:
*
* dbQueryExpression operator == (char const* field) {
* dbQueryExpression expr;
* expr = dbComponent(field,"jday"),"=",jday;
* return expr;
* }
*
* Making it possible to sepcify queries like this (assume that record has column "released" with type dbDate:
* * dbQuery q; * dbDate date; * q = date == "released"; **/ class FASTDB_DLL_ENTRY dbComponent { public: char const* structure; char const* field; dbComponent(char const* s, char const* f=NULL) : structure(s), field(f) {} }; /** * Class representing SubSQL expression. * It is mostly needed for implementation of application specific database types. * Look at the example in dbComponent class. * The effect of addeing dbExpression to the query is the same as if this expresion is enclosed in parenthesis. */ class FASTDB_DLL_ENTRY dbQueryExpression { friend class dbQuery; dbQueryElement* first; dbQueryElement** last; bool operand; public: dbQueryExpression& add(dbQueryElement::ElementType type, void const* ptr, dbTableDescriptor* table = NULL) { last = &(*last = new dbQueryElement(type, ptr, table))->next; operand = (type == dbQueryElement::qExpression); return *this; } dbQueryExpression& operator = (char const* ptr) { first = NULL, last = &first; return add(dbQueryElement::qExpression, ptr); } dbQueryExpression& operator = (dbComponent const& comp); dbQueryExpression& operator = (dbQueryExpression const& expr); dbQueryExpression& operator,(int1 const& ptr) { return add(dbQueryElement::qVarInt1, &ptr); } dbQueryExpression& operator,(int2 const& ptr) { return add(dbQueryElement::qVarInt2, &ptr); } dbQueryExpression& operator,(int4 const& ptr) { return add(dbQueryElement::qVarInt4, &ptr); } dbQueryExpression& operator,(db_int8 const& ptr) { return add(dbQueryElement::qVarInt8, &ptr); } dbQueryExpression& operator,(real4 const& ptr) { return add(dbQueryElement::qVarReal4, &ptr); } dbQueryExpression& operator,(real8 const& ptr) { return add(dbQueryElement::qVarReal8, &ptr); } dbQueryExpression& operator,(bool const& ptr) { return add(dbQueryElement::qVarBool, &ptr); } dbQueryExpression& operator,(char const* ptr) { return add(operand ? dbQueryElement::qVarString : dbQueryElement::qExpression, ptr); } dbQueryExpression& operator,(char const** ptr) { return add(dbQueryElement::qVarStringPtr, ptr); } dbQueryExpression& operator,(char** ptr) { return add(dbQueryElement::qVarStringPtr, ptr); } dbQueryExpression& operator,(void const* ptr) { return add(dbQueryElement::qVarRawData, ptr); } #ifdef USE_STD_STRING dbQueryExpression& operator,(std::string const& str) { return add(dbQueryElement::qVarStdString, &str); } #endif dbQueryExpression& operator,(dbQueryExpression const& expr) { *last = new dbQueryElement(dbQueryElement::qExpression, "("); (*last)->next = expr.first; last = expr.last; *last = new dbQueryElement(dbQueryElement::qExpression, ")"); last = &(*last)->next; operand = false; return *this; } dbQueryExpression& operator,(dbComponent const& comp) { add(dbQueryElement::qExpression, comp.structure); if (comp.field != NULL) { add(dbQueryElement::qExpression, "."); add(dbQueryElement::qExpression, comp.field); } operand = false; return *this; } dbQueryExpression& operator += (dbComponent const& comp) { return *this,comp; } dbQueryExpression& operator += (char const* ptr) { return add(dbQueryElement::qExpression, ptr); } #ifndef NO_MEMBER_TEMPLATES template
dbCompiledQuery class because each query is compiled only once - when
* it is executed first time. All subsequent executions of query used precompiled tree.
*/
class FASTDB_DLL_ENTRY dbQuery : public dbCompiledQuery {
friend class dbCompiler;
friend class dbDatabase;
friend class dbSubSql;
friend class dbCLI;
private:
dbMutex mutex;
dbQueryElement* elements;
dbQueryElement** nextElement;
bool operand;
bool mutexLocked;
//
// Prohibite query copying
//
dbQuery(dbQuery const&) {}
dbQuery& operator =(dbQuery const&) { return *this; }
public:
int pos; // position of condition in statement
char* dump(char* buf) {
char* p = buf;
for (dbQueryElement* elem = elements; elem != NULL; elem = elem->next) {
p = elem->dump(p);
}
return buf;
}
char* dumpValues(char* buf) {
char* p = buf;
for (dbQueryElement* elem = elements; elem != NULL; elem = elem->next) {
p = elem->dumpValues(p);
}
return buf;
}
dbQuery& append(dbQueryElement::ElementType type, void const* ptr,
dbTableDescriptor* table = NULL)
{
nextElement = &(*nextElement=new dbQueryElement(type,ptr,table))->next;
operand = (type == dbQueryElement::qExpression);
return *this;
}
dbQuery& reset();
//
// Redefined operator = and , make it possible to specify query in the
// following way:
// int x, y;
// dbDataTime dt;
// dbQuery q;
// dbCursordbUserFunctionArgument type)
* and should return integer, boolean, real or string value. Type of the function is detected by overloaded
* constructors. User defined function descriptor is cerated by USER_FUNC macro.
*/
class FASTDB_DLL_ENTRY dbUserFunction {
friend class dbDatabase;
friend class dbCompiler;
void* fptr;
char* name;
dbUserFunction* next;
static dbUserFunction* list;
enum funcType {
fInt2Bool,
fReal2Bool,
fStr2Bool,
fInt2Int,
fReal2Int,
fStr2Int,
fInt2Real,
fReal2Real,
fStr2Real,
fInt2Str,
fReal2Str,
fStr2Str,
fArg2Bool,
fArg2Int,
fArg2Real,
fArg2Str,
fArgArg2Bool,
fArgArg2Int,
fArgArg2Real,
fArgArg2Str,
fArgArgArg2Bool,
fArgArgArg2Int,
fArgArgArg2Real,
fArgArgArg2Str
};
int type;
void bind(char* name, void* f, funcType ftype);
public:
static dbUserFunction* find(char const* name) {
for (dbUserFunction* func = list; func != NULL; func = func->next) {
if (name == func->name) {
return func;
}
}
return NULL;
}
int getParameterType();
int getNumberOfParameters();
dbUserFunction(bool (*f)(db_int8), char* name) {
bind(name, (void*)f, fInt2Bool);
}
dbUserFunction(bool (*f)(real8), char* name) {
bind(name, (void*)f, fReal2Bool);
}
dbUserFunction(bool (*f)(char const*), char* name) {
bind(name, (void*)f, fStr2Bool);
}
dbUserFunction(db_int8 (*f)(db_int8), char* name) {
bind(name, (void*)f, fInt2Int);
}
dbUserFunction(db_int8 (*f)(real8), char* name) {
bind(name, (void*)f, fReal2Int);
}
dbUserFunction(db_int8 (*f)(char const*), char* name) {
bind(name, (void*)f, fStr2Int);
}
dbUserFunction(real8 (*f)(db_int8), char* name) {
bind(name, (void*)f, fInt2Real);
}
dbUserFunction(real8 (*f)(real8), char* name) {
bind(name, (void*)f, fReal2Real);
}
dbUserFunction(real8 (*f)(char const*), char* name) {
bind(name, (void*)f, fStr2Real);
}
dbUserFunction(char* (*f)(db_int8), char* name) {
bind(name, (void*)f, fInt2Str);
}
dbUserFunction(char* (*f)(real8), char* name) {
bind(name, (void*)f, fReal2Str);
}
dbUserFunction(char* (*f)(char const*), char* name) {
bind(name, (void*)f, fStr2Str);
}
dbUserFunction(bool (*f)(dbUserFunctionArgument&), char* name) {
bind(name, (void*)f, fArg2Bool);
}
dbUserFunction(char* (*f)(dbUserFunctionArgument&), char* name) {
bind(name, (void*)f, fArg2Str);
}
dbUserFunction(db_int8 (*f)(dbUserFunctionArgument&), char* name) {
bind(name, (void*)f, fArg2Int);
}
dbUserFunction(real8 (*f)(dbUserFunctionArgument&), char* name) {
bind(name, (void*)f, fArg2Real);
}
dbUserFunction(bool (*f)(dbUserFunctionArgument&, dbUserFunctionArgument&), char* name) {
bind(name, (void*)f, fArgArg2Bool);
}
dbUserFunction(char* (*f)(dbUserFunctionArgument&, dbUserFunctionArgument&), char* name) {
bind(name, (void*)f, fArgArg2Str);
}
dbUserFunction(db_int8 (*f)(dbUserFunctionArgument&, dbUserFunctionArgument&), char* name) {
bind(name, (void*)f, fArgArg2Int);
}
dbUserFunction(real8 (*f)(dbUserFunctionArgument&, dbUserFunctionArgument&), char* name) {
bind(name, (void*)f, fArgArg2Real);
}
dbUserFunction(bool (*f)(dbUserFunctionArgument&, dbUserFunctionArgument&, dbUserFunctionArgument&), char* name) {
bind(name, (void*)f, fArgArgArg2Bool);
}
dbUserFunction(char* (*f)(dbUserFunctionArgument&, dbUserFunctionArgument&, dbUserFunctionArgument&), char* name) {
bind(name, (void*)f, fArgArgArg2Str);
}
dbUserFunction(db_int8 (*f)(dbUserFunctionArgument&, dbUserFunctionArgument&, dbUserFunctionArgument&), char* name) {
bind(name, (void*)f, fArgArgArg2Int);
}
dbUserFunction(real8 (*f)(dbUserFunctionArgument&, dbUserFunctionArgument&, dbUserFunctionArgument&), char* name) {
bind(name, (void*)f, fArgArgArg2Real);
}
};
#endif