From cebc2c14a23b4e3661eb63c223ac59c0797f27f2 Mon Sep 17 00:00:00 2001 From: cxl Date: Wed, 7 Dec 2011 07:38:09 +0000 Subject: [PATCH] Sql: JoinRef (first iteration) git-svn-id: svn://ultimatepp.org/upp/trunk@4264 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/Sql/IntroSch.cpp | 81 +++++++++++++++++++++++++++++++++++ uppsrc/Sql/Sql.upp | 1 + uppsrc/Sql/SqlSchema.h | 15 +++++++ uppsrc/Sql/SqlStatement.cpp | 85 +++++++++++++++++++++++++++++++------ uppsrc/Sql/Sqlexp.h | 11 ++++- uppsrc/Sql/sch_source.h | 16 +++++++ 6 files changed, 193 insertions(+), 16 deletions(-) create mode 100644 uppsrc/Sql/IntroSch.cpp diff --git a/uppsrc/Sql/IntroSch.cpp b/uppsrc/Sql/IntroSch.cpp new file mode 100644 index 000000000..3c2f9843f --- /dev/null +++ b/uppsrc/Sql/IntroSch.cpp @@ -0,0 +1,81 @@ +#include "Sql.h" + +NAMESPACE_UPP + +ArrayMap& sSchTableInfo() +{ + static ArrayMap x; + return x; +} + +SchTableInfo& SchTableInfo::Column(const char *name) +{ + column.Add(name); + ref_table.Add(); + ref_column.Add(); + return *this; +} + +SchTableInfo& SchTableInfo::References(const char *table) +{ + ref_table.Top() = table; + return *this; +} + +SchTableInfo& SchTableInfo::References(const char *table, const char *column) +{ + References(table); + ref_column.Top() = column; + return *this; +} + +SchTableInfo& SchDbInfo(const char *table) +{ + return sSchTableInfo().GetAdd(table); +} + +const SchTableInfo& GetSchTableInfo(const String& table) +{ + static SchTableInfo sSchTableInfoZero; + return sSchTableInfo().Get(~table, sSchTableInfoZero); +} + +SqlBool Join(const String& tab1, const String& tab2) +{ + const SchTableInfo& t1 = GetSchTableInfo(tab1); + const SchTableInfo& t2 = GetSchTableInfo(tab2); + for(int i = 0; i < t1.ref_table.GetCount(); i++) + if(t1.ref_table[i] == tab2) + return SqlId(t1.column[i]).Of(SqlId(tab1)) == SqlId(t2.column[0]).Of(SqlId(tab2)); + for(int i = 0; i < t2.ref_table.GetCount(); i++) + if(t2.ref_table[i] == tab1) + return SqlId(t2.column[i]).Of(SqlId(tab2)) == SqlId(t1.column[0]).Of(SqlId(tab1)); + return SqlBool::False(); +} + +SqlBool FindSchJoin(const String& tables) +{ + INTERLOCKED { + static VectorMap cache; + if(cache.GetCount() > 20000) + cache.Clear(); + int q = cache.Find(tables); + if(q >= 0) + return cache[q]; + Vector s = Split(tables, ','); + if(s.GetCount() >= 2) { + String tab1 = s.Top(); + for(int i = 0; i < s.GetCount() - 1; i++) { + SqlBool b = Join(tab1, s[i]); + if(!b.IsFalse()) { + cache.Add(tables, b); + return b; + } + } + } + NEVER(); + return SqlBool::False(); + } +} + +END_UPP_NAMESPACE \ No newline at end of file diff --git a/uppsrc/Sql/Sql.upp b/uppsrc/Sql/Sql.upp index af8a35fac..98773a631 100644 --- a/uppsrc/Sql/Sql.upp +++ b/uppsrc/Sql/Sql.upp @@ -27,6 +27,7 @@ file sch_source.h, sch_schema.h, util_td.cpp, + IntroSch.cpp, ExportSch.cpp, Info readonly separator, src.tpp, diff --git a/uppsrc/Sql/SqlSchema.h b/uppsrc/Sql/SqlSchema.h index ed85cebe0..a255cf7cd 100644 --- a/uppsrc/Sql/SqlSchema.h +++ b/uppsrc/Sql/SqlSchema.h @@ -108,6 +108,21 @@ inline void SqlSchemaClear(T *a, int n) { SqlSchemaClear(*a++); } + +struct SchTableInfo { + Vector column; + Vector ref_table; + Vector ref_column; + + SchTableInfo& Column(const char *name); + SchTableInfo& References(const char *table); + SchTableInfo& References(const char *table, const char *column); +}; + +SchTableInfo& SchDbInfo(const char *table); + +SqlBool FindSchJoin(const String& tables); + String ExportSch(SqlSession& session, const String& database); String ExportIds(SqlSession& session, const String& database); diff --git a/uppsrc/Sql/SqlStatement.cpp b/uppsrc/Sql/SqlStatement.cpp index ef976f668..5a628dc6f 100644 --- a/uppsrc/Sql/SqlStatement.cpp +++ b/uppsrc/Sql/SqlStatement.cpp @@ -66,12 +66,6 @@ SqlSelect& SqlSelect::Where(const SqlBool& exp) { return *this; } -SqlSelect& SqlSelect::On(const SqlBool& exp) { - if(!exp.IsTrue() && !exp.IsEmpty()) - text << " on " << ~exp; - return *this; -} - SqlSelect& SqlSelect::StartWith(const SqlBool& exp) { text << " start with " << ~exp; return *this; @@ -143,42 +137,103 @@ SqlSelect& SqlSelect::Get() { } SqlSelect& SqlSelect::From(const SqlSet& table) { - text = "select " + text + " from " + table(SqlSet::SETOP + 1); + String ts = table(SqlSet::SETOP + 1); + text = "select " + text + " from " + ts; + tables << ',' << Filter(ts, CharFilterNotWhitespace); + on = false; return *this; } SqlSelect& SqlSelect::From(SqlId table) { - text = "select " + text + " from " + ~table; + String t1 = ~table; + text = "select " + text + " from " + t1; + tables << ',' << t1; + on = false; return *this; } SqlSelect& SqlSelect::From(SqlId table1, SqlId table2) { - text = "select " + text + " from " + ~table1 + ", " + ~table2; + String t1 = ~table1; + String t2 = ~table2; + text = "select " + text + " from " + t1 + ", " + t2; + tables << ',' << t1 << ',' << t2; + on = false; return *this; } SqlSelect& SqlSelect::From(SqlId table1, SqlId table2, SqlId table3) { - text = "select " + text + " from " + ~table1 + ", " + ~table2 + ", " + ~table3; + String t1 = ~table1; + String t2 = ~table2; + String t3 = ~table3; + text = "select " + text + " from " + t1 + ", " + t2 + ", " + t3; + tables << ',' << t1 << ',' << t2 << ',' << t3; + on = false; return *this; } SqlSelect& SqlSelect::InnerJoin0(const String& table) { - text << " inner join " << ~table; + text << " inner join " << table; + tables << ',' << table; + on = false; return *this; } SqlSelect& SqlSelect::LeftJoin0(const String& table) { - text << " left outer join " << ~table; + text << " left outer join " << table; + tables << ',' << table; + on = false; return *this; } SqlSelect& SqlSelect::RightJoin0(const String& table) { - text << " right outer join " << ~table; + text << " right outer join " << table; + tables << ',' << table; + on = false; return *this; } SqlSelect& SqlSelect::FullJoin0(const String& table) { - text << " full outer join " << ~table; + text << " full outer join " << table; + tables << ',' << table; + on = false; + return *this; +} + +SqlSelect& SqlSelect::InnerJoinRef(SqlId table) +{ + InnerJoin(table); + On(FindSchJoin(tables)); + on = true; + return *this; +} + +SqlSelect& SqlSelect::LeftJoinRef(SqlId table) +{ + LeftJoin(table); + On(FindSchJoin(tables)); + on = true; + return *this; +} + +SqlSelect& SqlSelect::RightJoinRef(SqlId table) +{ + RightJoin(table); + On(FindSchJoin(tables)); + on = true; + return *this; +} + +SqlSelect& SqlSelect::FullJoinRef(SqlId table) +{ + FullJoin(table); + On(FindSchJoin(tables)); + on = true; + return *this; +} + +SqlSelect& SqlSelect::On(const SqlBool& exp) { + if(!exp.IsTrue() && !exp.IsEmpty()) + text << (on ? " and " : " on ") << ~exp; return *this; } @@ -196,6 +251,7 @@ SqlSelect SqlSelect::AsTable(SqlId tab) const SqlSelect::SqlSelect(Fields f) { + on = false; SqlSet set(f); text = ~set; } @@ -204,6 +260,7 @@ SqlSelect::SqlSelect(Fields f) #define E__QSqlSelectF(I) \ SqlSelect::SqlSelect(__List##I(E__SqlVal)) { \ + on = false; \ SqlSet set; \ __List##I(E__SCat); \ text = ~set; \ diff --git a/uppsrc/Sql/Sqlexp.h b/uppsrc/Sql/Sqlexp.h index cd9e1fefb..5bfe299a2 100644 --- a/uppsrc/Sql/Sqlexp.h +++ b/uppsrc/Sql/Sqlexp.h @@ -484,6 +484,8 @@ public: class SqlSelect { String text; + String tables; + bool on; SqlSelect& InnerJoin0(const String& table); SqlSelect& LeftJoin0(const String& table); @@ -515,6 +517,11 @@ public: SqlSelect& RightJoin(const SqlSet& set) { return RightJoin0(~set(SqlSet::SET)); } SqlSelect& FullJoin(const SqlSet& set) { return FullJoin0(~set(SqlSet::SET)); } + SqlSelect& InnerJoinRef(SqlId table); + SqlSelect& LeftJoinRef(SqlId table); + SqlSelect& RightJoinRef(SqlId table); + SqlSelect& FullJoinRef(SqlId table); + SqlSelect& Where(const SqlBool& exp); SqlSelect& On(const SqlBool& exp); SqlSelect& StartWith(const SqlBool& exp); @@ -541,8 +548,8 @@ public: SqlSelect AsTable(SqlId tab) const; SqlSelect(Fields f); - SqlSelect(const SqlSet& s) { text = ~s; } - SqlSelect() {} + SqlSelect(const SqlSet& s) { text = ~s; on = false; } + SqlSelect() { on = false; } #define E__QSelect(I) SqlSelect(__List##I(E__SqlVal)); __Expand(E__QSelect); #undef E__QSelect diff --git a/uppsrc/Sql/sch_source.h b/uppsrc/Sql/sch_source.h index e89bcfea2..906bd6130 100644 --- a/uppsrc/Sql/sch_source.h +++ b/uppsrc/Sql/sch_source.h @@ -125,3 +125,19 @@ void S_##x::FieldLayoutRaw(FieldOperator& fo, const String& prefix) {\ #define END_TYPE } #include SCHEMADIALECT + +// Introspection + +#define TYPE(x) struct SINS_##x##_ { SINS_##x##_(); } SINS_##x##__; SINS_##x##_::SINS_##x##_() { SchDbInfo(#x) +#define TYPE_I(x, b) struct SINS_##x##_ { SINS_##x##_(); } SINS_##x##__; SINS_##x##_::SINS_##x##_() { SchDbInfo(#x) +#define TYPE_II(x, b1, b2) struct SINS_##x##_ { SINS_##x##_(); } SINS_##x##__; SINS_##x##_::SINS_##x##_() { SchDbInfo(#x) +#define TYPE_III(x, b1, b2, b3) struct SINS_##x##_ { SINS_##x##_(); } SINS_##x##__; SINS_##x##_::SINS_##x##_() { SchDbInfo(#x) +#define COLUMN(type, ctype, name, width, prec) .Column(#name) +#define REFERENCES(table) .References(#table) +#define REFERENCES_CASCADE(table) .References(#table) +#define REFERENCES_(table, column) .References(#table, #column) +#define REFERENCES_CASCADE_(table, column) .References(#table, #column) +#define COLUMN_ARRAY(type, ctype, name, width, prec, items) .ColumnArray(#name, items); +#define END_TABLE ; } + +#include SCHEMADIALECT