summaryrefslogtreecommitdiff
path: root/lib/dbdict.h
diff options
context:
space:
mode:
authorhorchi <vdr@jwendel.de>2017-03-05 16:39:28 +0100
committerhorchi <vdr@jwendel.de>2017-03-05 16:39:28 +0100
commite2a48d8701f91b8e24fbe9e99e91eb72a87bb749 (patch)
tree726f70554b4ca985a09ef6e30a7fdc8df089993c /lib/dbdict.h
downloadvdr-epg-daemon-e2a48d8701f91b8e24fbe9e99e91eb72a87bb749.tar.gz
vdr-epg-daemon-e2a48d8701f91b8e24fbe9e99e91eb72a87bb749.tar.bz2
git init1.1.103
Diffstat (limited to 'lib/dbdict.h')
-rw-r--r--lib/dbdict.h471
1 files changed, 471 insertions, 0 deletions
diff --git a/lib/dbdict.h b/lib/dbdict.h
new file mode 100644
index 0000000..2999390
--- /dev/null
+++ b/lib/dbdict.h
@@ -0,0 +1,471 @@
+/*
+ * dbdict.h
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#ifndef __DBDICT_H
+#define __DBDICT_H
+
+#include <stdio.h>
+
+#include <vector>
+#include <map>
+#include <string>
+
+class cDbDict;
+
+typedef int (*FilterFromName)(const char* name);
+
+//***************************************************************************
+// _casecmp_
+//***************************************************************************
+
+class _casecmp_
+{
+ public:
+
+ bool operator() (const std::string& a, const std::string& b) const
+ {
+ return strcasecmp(a.c_str(), b.c_str()) < 0;
+ }
+};
+
+//***************************************************************************
+// cDbService
+//***************************************************************************
+
+class cDbService
+{
+ public:
+
+ enum Misc
+ {
+ maxIndexFields = 20
+ };
+
+ enum FieldFormat
+ {
+ ffUnknown = na,
+
+ ffInt,
+ ffUInt,
+ ffBigInt,
+ ffUBigInt,
+ ffAscii, // -> VARCHAR
+ ffText,
+ ffMText,
+ ffMlob, // -> MEDIUMBLOB
+ ffFloat,
+ ffDateTime,
+
+ ffCount
+ };
+
+ enum FieldType
+ {
+ ftUnknown = na,
+ ftNo = 0,
+
+ ftData = 1,
+ ftPrimary = 2,
+ ftMeta = 4,
+ ftAutoinc = 8,
+
+ ftAll = ftData | ftPrimary | ftMeta
+ };
+
+ enum BindType
+ {
+ bndIn = 0x001,
+ bndOut = 0x002,
+ bndSet = 0x004
+ };
+
+ enum ProcType
+ {
+ ptProcedure,
+ ptFunction
+ };
+
+ struct TypeDef
+ {
+ FieldType type;
+ const char* name;
+ };
+
+ static const char* toString(FieldFormat t);
+ static FieldFormat toDictFormat(const char* format);
+ static const char* formats[];
+ static const char* dictFormats[];
+
+ static int toType(const char* type);
+ static const char* toName(FieldType type, char* buf);
+ static TypeDef types[];
+};
+
+typedef cDbService cDBS;
+
+//***************************************************************************
+// cDbFieldDef
+//***************************************************************************
+
+class cDbFieldDef : public cDbService
+{
+ public:
+
+ friend class cDbDict;
+
+ cDbFieldDef()
+ {
+ name = 0;
+ dbname = 0,
+ format = ffUnknown;
+ size = na;
+ type = ftUnknown;
+ description = 0;
+ dbdescription = 0;
+ filter = 0xFFFF;
+ def = 0;
+ }
+
+ cDbFieldDef(const char* n, const char* dn, FieldFormat f, int s, int t, int flt = 0xFFFF)
+ {
+ name = strdup(n);
+ dbname = strdup(dn);
+ format = f;
+ size = s;
+ type = t;
+ filter = flt;
+ description = 0;
+ dbdescription = 0;
+ def = 0;
+ }
+
+ ~cDbFieldDef() { free(name); free(dbname); free(description); free(dbdescription); free(def); }
+
+ int getIndex() { return index; }
+ const char* getName() { return name; }
+ int hasName(const char* n) { return strcasecmp(n, name) == 0; }
+ int hasDbName(const char* n) { return strcasecmp(n, dbname) == 0; }
+ const char* getDescription() { return description; }
+ const char* getDbDescription() { return dbdescription; }
+ const char* getDbName() { return dbname; }
+ int getSize() { return size; }
+ FieldFormat getFormat() { return format; }
+ int getType() { return type; }
+ const char* getDefault() { return def ? def : ""; }
+ int getFilter() { return filter; }
+ int filterMatch(int f) { return !f || filter & f; }
+ int hasType(int types) { return types & type; }
+ int hasFormat(int f) { return format == f; }
+
+ int isString() { return format == ffAscii || format == ffText ||
+ format == ffMText || format == ffMlob; }
+ int isInt() { return format == ffInt || format == ffUInt; }
+ int isBigInt() { return format == ffBigInt || format == ffUBigInt; }
+ int isFloat() { return format == ffFloat; }
+ int isDateTime() { return format == ffDateTime; }
+
+ void setDescription(const char* desc)
+ {
+ description = strdup(desc);
+ dbdescription = strdup(strReplace("'", "\\'", description).c_str());
+ }
+
+ const char* toColumnFormat(char* buf) // column type to be used for create/alter
+ {
+ if (!buf)
+ return 0;
+
+ sprintf(buf, "%s", toString(format));
+
+ if (format != ffMlob)
+ {
+ if (!size)
+ {
+ if (format == ffAscii)
+ size = 100;
+ else if (format == ffInt || format == ffUInt || format == ffBigInt || format == ffUBigInt)
+ size = 11;
+ else if (format == ffFloat)
+ size = 10;
+ }
+
+ if (format == ffFloat)
+ sprintf(eos(buf), "(%d,%d)", size/10 + size%10, size%10); // 62 -> 8,2
+ else if (format == ffInt || format == ffUInt || format == ffBigInt || format == ffUBigInt || format == ffAscii)
+ sprintf(eos(buf), "(%d)", size);
+
+ if (format == ffUInt || format == ffUBigInt)
+ sprintf(eos(buf), " unsigned");
+ }
+
+ return buf;
+ }
+
+ int isValid()
+ {
+ if (!name) { tell(0, "Missing field name"); return no; }
+ if (!dbname) { tell(0, "Missing fields database name"); return no; }
+ if (size == na) { tell(0, "Missing field size"); return no; }
+ if (type == ftUnknown) { tell(0, "Missing or invalid field type"); return no; }
+ if (format == ffUnknown) { tell(0, "Missing or invalid field format"); return no; }
+
+ return yes;
+ }
+
+ void show()
+ {
+ char colFmt[100];
+ char fType[100];
+ char tmp[100];
+
+ sprintf(fType, "(%s)", toName((FieldType)type, tmp));
+
+ tell(0, "%-20s %-25s %-17s %-20s (0x%04X) default '%s' '%s'", name, dbname,
+ toColumnFormat(colFmt), fType, filter, notNull(def, ""), description);
+ }
+
+ protected:
+
+ char* name;
+ char* dbname;
+ char* description;
+ char* dbdescription;
+ FieldFormat format;
+ int size;
+ int index;
+ int type;
+ int filter; // bitmask (defaults to 0xFFFF)
+ char* def;
+};
+
+//***************************************************************************
+// cDbIndexDef
+//***************************************************************************
+
+class cDbIndexDef
+{
+ public:
+
+ cDbIndexDef() { name = 0; description = 0; }
+ ~cDbIndexDef() { free(name); free(description); }
+
+ void setName(const char* n) { free(name); name = strdup(n); }
+ const char* getName() { return name; }
+
+ void setDescription(const char* d) { free(description); description = strdup(d); }
+ const char* getDescription() { return description; }
+
+ int fieldCount() { return dfields.size(); }
+ void addField(cDbFieldDef* f) { dfields.push_back(f); }
+ cDbFieldDef* getField(int i) { return dfields[i]; }
+
+ void show()
+ {
+ std::string s = "";
+
+ for (uint i = 0; i < dfields.size(); i++)
+ s += dfields[i]->getName() + std::string(" ");
+
+ s.erase(s.find_last_not_of(' ')+1);
+
+ tell(0, "Index %-25s (%s)", getName(), s.c_str());
+ }
+
+ protected:
+
+ char* name;
+ char* description;
+ std::vector<cDbFieldDef*> dfields; // index fields
+};
+
+//***************************************************************************
+// cDbTableDef
+//***************************************************************************
+
+class cDbTableDef : public cDbService
+{
+ public:
+
+ friend class cDbRow;
+ friend class cDbTable;
+ friend class cDbStatement;
+
+ cDbTableDef(const char* n) { name = strdup(n); }
+
+ ~cDbTableDef()
+ {
+ for (uint i = 0; i < indices.size(); i++)
+ delete indices[i];
+
+ indices.clear();
+
+ free(name);
+ clear();
+ }
+
+ const char* getName() { return name; }
+ int fieldCount() { return dfields.size(); }
+ cDbFieldDef* getField(int id) { return _dfields[id]; }
+
+ cDbFieldDef* getField(const char* fname, int silent = no)
+ {
+ std::map<std::string, cDbFieldDef*, _casecmp_>::iterator f;
+
+ if ((f = dfields.find(fname)) != dfields.end())
+ return f->second;
+
+ if (!silent)
+ tell(0, "Fatal: Missing definition of field '%s.%s' in dictionary!", name, fname);
+
+ return 0;
+ }
+
+ cDbFieldDef* getFieldByDbName(const char* dbname)
+ {
+ std::map<std::string, cDbFieldDef*, _casecmp_>::iterator it;
+
+ for (it = dfields.begin(); it != dfields.end(); it++)
+ {
+ if (it->second->hasDbName(dbname))
+ return it->second;
+ }
+
+ tell(5, "Fatal: Missing definition of field '%s.%s' in dictionary!", name, dbname);
+
+ return 0;
+ }
+
+ void addField(cDbFieldDef* f)
+ {
+ if (dfields.find(f->getName()) == dfields.end())
+ {
+ dfields[f->getName()] = f; // add to named map
+ _dfields.push_back(f); // add to indexed list
+ }
+ else
+ tell(0, "Fatal: Field '%s.%s' doubly defined", getName(), f->getName());
+ }
+
+ int indexCount() { return indices.size(); }
+ cDbIndexDef* getIndex(int i) { return indices[i]; }
+ void addIndex(cDbIndexDef* i) { indices.push_back(i); }
+
+ void clear()
+ {
+ std::map<std::string, cDbFieldDef*>::iterator f;
+
+ while ((f = dfields.begin()) != dfields.end())
+ {
+ if (f->second)
+ delete f->second;
+
+ dfields.erase(f);
+ }
+ }
+
+ void show()
+ {
+ // show fields
+
+ for (uint i = 0; i < _dfields.size(); i++)
+ _dfields[i]->show();
+
+ // show indices
+
+ if (!indices.size())
+ {
+ tell(0, " ");
+ return;
+ }
+
+ tell(0, "-----------------------------------------------------");
+ tell(0, "Indices from '%s'", getName());
+ tell(0, "-----------------------------------------------------");
+
+ for (uint i = 0; i < indices.size(); i++)
+ indices[i]->show();
+
+ tell(0, " ");
+ }
+
+ private:
+
+ char* name;
+ std::vector<cDbIndexDef*> indices;
+
+ // FiledDefs stored as list to have access via index
+ std::vector<cDbFieldDef*> _dfields;
+
+ // same FiledDef references stored as a map to have access via name
+ std::map<std::string, cDbFieldDef*, _casecmp_> dfields;
+};
+
+//***************************************************************************
+// cDbDict
+//***************************************************************************
+
+class cDbDict : public cDbService
+{
+ public:
+
+ // declarations
+
+ enum TableDictToken
+ {
+ dtName,
+ dtDescription,
+ dtDbName,
+ dtFormat,
+ dtSize,
+ dtType,
+
+ dtCount
+ };
+
+ enum IndexDictToken
+ {
+ idtName,
+ idtDescription,
+ idtFields
+ };
+
+ cDbDict();
+ virtual ~cDbDict();
+
+ int in(const char* file, int filter = 0);
+ void setFilterFromNameFct(FilterFromName fct) { fltFromNameFct = fct; }
+
+ cDbTableDef* getTable(const char* name);
+ void show();
+ int init(cDbFieldDef*& field, const char* tname, const char* fname);
+ const char* getPath() { return path ? path : ""; }
+ void forget();
+
+ std::map<std::string, cDbTableDef*>::iterator getFirstTableIterator() { return tables.begin(); }
+ std::map<std::string, cDbTableDef*>::iterator getTableEndIterator() { return tables.end(); }
+
+ protected:
+
+ int atLine(const char* line);
+ int parseField(const char* line);
+ int parseIndex(const char* line);
+ int parseFilter(cDbFieldDef* f, const char* value);
+
+ // data
+
+ int inside;
+ cDbTableDef* curTable;
+ std::map<std::string, cDbTableDef*, _casecmp_> tables;
+ char* path;
+ int fieldFilter;
+ FilterFromName fltFromNameFct;
+};
+
+extern cDbDict dbDict;
+
+//***************************************************************************
+#endif // __DBDICT_H