aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--odb/statement-processing-common.hxx45
-rw-r--r--odb/statement-processing.cxx27
-rw-r--r--odb/statement.hxx2
3 files changed, 62 insertions, 12 deletions
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<std::size_t> (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<std::size_t> (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<std::size_t> (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