From b8c4c3b3f3cc755d537fd3f7f1f613fbd5a3957b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 6 Feb 2015 08:57:30 +0200 Subject: Implement join types support in views --- odb/statement-processing-common.hxx | 45 +++++++++++++++++++++++++++++++++++-- odb/statement-processing.cxx | 27 ++++++++++++++-------- odb/statement.hxx | 2 +- 3 files changed, 62 insertions(+), 12 deletions(-) (limited to 'odb') diff --git a/odb/statement-processing-common.hxx b/odb/statement-processing-common.hxx index 4c12791..5703641 100644 --- a/odb/statement-processing-common.hxx +++ b/odb/statement-processing-common.hxx @@ -33,6 +33,20 @@ namespace odb return 0; } + static inline const char* + find (const char* b, const char* e, const char* s, std::size_t n) + { + for (; b != e; ++b) + { + if (*b == *s && + static_cast (e - b) >= n && + traits::compare (b, s, n) == 0) + return b; + } + + return 0; + } + // Iterate over INSERT column/value list, UPDATE SET expression list, // or SELECT column/join list. // @@ -97,6 +111,30 @@ namespace odb } } + // Only allows A-Z and spaces before prefix (e.g., JOIN in LEFT OUTER JOIN). + // + static inline bool + fuzzy_prefix (const char* b, + const char* end, + const char* prefix, + std::size_t prefix_size) + { + for (; b != end; ++b) + { + char c (*b); + + if ((c < 'A' || c > 'Z') && c != ' ') + break; + + if (c == *prefix && + static_cast (end - b) > prefix_size && + traits::compare (b, prefix, prefix_size) == 0) + return true; + } + + return false; + } + static inline const char* newline_begin (const char* b, const char* end) { @@ -111,7 +149,8 @@ namespace odb const char*& e, const char* end, const char* prefix, - std::size_t prefix_size) + std::size_t prefix_size, + bool prefix_fuzzy = false) { if (e != end) e++; // Skip past '\n'. @@ -121,7 +160,9 @@ namespace odb // Do we have another element? // if (static_cast (end - b) > prefix_size && - traits::compare (b, prefix, prefix_size) == 0) + (prefix_fuzzy + ? fuzzy_prefix (b, end, prefix, prefix_size) + : traits::compare (b, prefix, prefix_size) == 0)) { e = find (b, end, '\n'); if (e == 0) diff --git a/odb/statement-processing.cxx b/odb/statement-processing.cxx index 3920995..dde4c39 100644 --- a/odb/statement-processing.cxx +++ b/odb/statement-processing.cxx @@ -480,14 +480,14 @@ namespace odb // JOIN list. // const char* joins_begin (0), *joins_end (0); - if (e - p > 5 && traits::compare (p, "LEFT JOIN ", 10) == 0) + if (e - p > 5 && fuzzy_prefix (p, e, "JOIN ", 5)) { joins_begin = p; // Find the end of the JOIN list. // for (const char* je (newline_begin (p, e)); - je != 0; newline_next (p, je, e, "LEFT JOIN ", 10)) + je != 0; newline_next (p, je, e, "JOIN ", 5, true)) ; joins_end = (p != e ? p - 1 : p); @@ -580,7 +580,9 @@ namespace odb // Get the alias or, if none used, the table name. // - p = find (j + 10, je, ' '); // 10 for "LEFT JOIN ". + p = find (j, je, "JOIN ", 5) + 5; // Skip past "JOIN ". + const char* table_begin (p); + p = find (p, je, ' '); // End of the table name. const char* table_end (p); p++; // Skip space. @@ -588,17 +590,24 @@ namespace odb // const char* alias_begin (0); size_t alias_size (0); - if (je - p > 3 && traits::compare (p, "ON ", 3) != 0) + + if (p != je && // Not the end. + (je - p < 4 || traits::compare (p, "ON ", 3) != 0)) { + // Something other than "ON ", so got to be an alias. + // if (as) p += 3; alias_begin = p; - alias_size = find (p, je, ' ') - alias_begin; + p = find (p, je, ' '); // There might be no ON (CROSS JOIN). + alias_size = (p != 0 ? p : je) - alias_begin; } else { - alias_begin = j + 10; + // Just the table. + // + alias_begin = table_begin; alias_size = table_end - alias_begin; } @@ -613,7 +622,7 @@ namespace odb // // Instead of re-parsing the whole thing again, we are going to // take a shortcut and simply search for the alias in the statement - // we have constructed so far (that's why we have have added the + // we have constructed so far (that's why we have added the // trailer before filling in the JOINs). To make it more robust, // we are going to do a few extra sanity checks, specifically, // that the alias is a top level identifier and is followed by @@ -636,10 +645,10 @@ namespace odb continue; // The only way to distinguish the [a].[c] from FROM [a].[c] or - // LEFT JOIN [a].[c] is by checking the prefix. + // JOIN [a].[c] is by checking the prefix. // if ((p > 5 && r.compare (p - 5, 5, "FROM ") == 0) || - (p > 10 && r.compare (p - 10, 10, "LEFT JOIN ") == 0)) + (p > 5 && r.compare (p - 5, 5, "JOIN ") == 0)) continue; // Check that we are followed by a single identifier. diff --git a/odb/statement.hxx b/odb/statement.hxx index 3cecd53..bac8414 100644 --- a/odb/statement.hxx +++ b/odb/statement.hxx @@ -85,7 +85,7 @@ namespace odb // [schema.]table.a,\n // alias.b\n // FROM [schema.]table[\n] - // [LEFT JOIN [schema.]table [AS alias] ON ...[\n]]* + // [{A-Z }* JOIN [schema.]table [AS alias][ ON ...][\n]]* // [WHERE ...] // static void -- cgit v1.1