summaryrefslogtreecommitdiff
path: root/odb/statement-processing.cxx
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2024-01-24 16:53:38 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2024-01-24 16:53:38 +0300
commit26e36b3a9d7b49d46ecfa69b447482251acba8ac (patch)
tree5436b7857fae9aee50d018ea0eef35a529fc03e4 /odb/statement-processing.cxx
parent0074faad1b27f3cd52a606c438e4f1375956d731 (diff)
Turn libodb repository into package for muti-package repositorylibodb
Diffstat (limited to 'odb/statement-processing.cxx')
-rw-r--r--odb/statement-processing.cxx685
1 files changed, 0 insertions, 685 deletions
diff --git a/odb/statement-processing.cxx b/odb/statement-processing.cxx
deleted file mode 100644
index 708c9ab..0000000
--- a/odb/statement-processing.cxx
+++ /dev/null
@@ -1,685 +0,0 @@
-// file : odb/statement-processing.cxx
-// license : GNU GPL v2; see accompanying LICENSE file
-
-#include <cassert>
-
-#include <odb/statement-processing-common.hxx>
-
-#ifdef LIBODB_TRACE_STATEMENT_PROCESSING
-# include <iostream>
-#endif
-
-#include <odb/statement.hxx>
-
-using namespace std;
-
-namespace odb
-{
- typedef const void* const* bind_type;
-
- static inline const void*
- bind_at (size_t i, bind_type bind, size_t bind_skip)
- {
- const char* b (reinterpret_cast<const char*> (bind));
- return *reinterpret_cast<bind_type> (b + i * bind_skip);
- }
-
- void statement::
- process_insert (string& r,
- const char* s,
- bind_type bind,
- size_t bind_size,
- size_t bind_skip,
- char param_symbol,
- char param_symbol2)
- {
-#ifndef LIBODB_DEBUG_STATEMENT_PROCESSING
- assert (bind_size != 0); // Cannot be versioned.
-#endif
-
- bool fast (true); // Fast case (if all present).
- for (size_t i (0); i != bind_size && fast; ++i)
- {
- if (bind_at (i, bind, bind_skip) == 0)
- fast = false;
- }
-
- // Fast path: just remove the "structure".
- //
-#ifndef LIBODB_DEBUG_STATEMENT_PROCESSING
- if (fast)
- {
- process_fast (s, r);
- return;
- }
-#endif
-
- // Scan the statement and store the positions of various parts.
- //
- size_t n (traits::length (s));
- const char* e (s + n);
-
- // Header.
- //
- const char* p (find (s, e, '\n'));
- assert (p != 0);
- size_t header_size (p - s);
- p++;
-
- // Column list.
- //
- const char* columns_begin (0);
- if (*p == '(')
- {
- columns_begin = p;
-
- // Find the end of the column list.
- //
- for (const char* ce (paren_begin (p, e)); ce != 0; paren_next (p, ce, e))
- ;
- }
-
- // OUTPUT
- //
- const char* output_begin (0);
- size_t output_size (0);
- if (e - p > 7 && traits::compare (p, "OUTPUT ", 7) == 0)
- {
- output_begin = p;
- p += 7;
- p = find (p, e, '\n');
- assert (p != 0);
- output_size = p - output_begin;
- p++;
- }
-
- // VALUES or DEFAULT VALUES
- //
- bool empty (true); // DEFAULT VALUES case (if none present).
- const char* values_begin (0);
- if (e - p > 7 && traits::compare (p, "VALUES\n", 7) == 0)
- {
- p += 7;
- values_begin = p;
-
- size_t bi (0);
- for (const char* ve (paren_begin (p, e)); ve != 0; paren_next (p, ve, e))
- {
- // We cannot be empty if we have a non-parameterized value, e.g.,
- // INSERT ... VALUES(1,?). We also cannot be empty if this value
- // is present in the bind array.
- //
- if ((find (p, ve, param_symbol) == 0 &&
- (param_symbol2 == '\0' || find (p, ve, param_symbol2) == 0)) ||
- bind_at (bi++, bind, bind_skip) != 0)
- empty = false;
- }
- }
- else
- {
- // Must be DEFAULT VALUES.
- //
- assert (traits::compare (p, "DEFAULT VALUES", 14) == 0);
- p += 14;
-
- if (*p == '\n')
- p++;
- }
-
- // Trailer.
- //
- const char* trailer_begin (0);
- size_t trailer_size (0);
- if (e - p != 0)
- {
- trailer_begin = p;
- trailer_size = e - p;
- }
-
- // Empty case.
- //
- if (empty)
- {
- r.reserve (header_size +
- (output_size == 0 ? 0 : output_size + 1) +
- 15 + // For " DEFAULT VALUES"
- (trailer_size == 0 ? 0 : trailer_size + 1));
-
- r.assign (s, header_size);
-
- if (output_size != 0)
- {
- r += ' ';
- r.append (output_begin, output_size);
- }
-
- r += " DEFAULT VALUES";
-
- if (trailer_size != 0)
- {
- r += ' ';
- r.append (trailer_begin, trailer_size);
- }
-
-#ifdef LIBODB_TRACE_STATEMENT_PROCESSING
- if (r.size () != n)
- cerr << endl
- << "old: '" << s << "'" << endl << endl
- << "new: '" << r << "'" << endl << endl;
-#endif
-
- return;
- }
-
- // Assume the same size as the original. It can only shrink, and in
- // most cases only slightly. So this is a good approximation.
- //
- r.reserve (n);
- r.assign (s, header_size);
-
- // Column list.
- //
- {
- r += ' ';
-
- size_t i (0), bi (0);
-
- for (const char *c (columns_begin), *ce (paren_begin (c, e)),
- *v (values_begin), *ve (paren_begin (v, e));
- ce != 0; paren_next (c, ce, e), paren_next (v, ve, e))
- {
- // See if the value contains the parameter symbol and, if so,
- // whether it is present in the bind array.
- //
- if ((find (v, ve, param_symbol) != 0 ||
- (param_symbol2 != '\0' && find (v, ve, param_symbol2) != 0)) &&
- bind_at (bi++, bind, bind_skip) == 0)
- continue;
-
- // Append the column.
- //
- if (i++ == 0)
- r += '(';
- else
- r += ", "; // Add the space for consistency with the fast path.
-
- r.append (c, ce - c);
- }
-
- r += ')';
- }
-
- // OUTPUT
- //
- if (output_size != 0)
- {
- r += ' ';
- r.append (output_begin, output_size);
- }
-
- // Value list.
- //
- {
- r += " VALUES ";
-
- size_t i (0), bi (0);
-
- for (const char* v (values_begin), *ve (paren_begin (v, e));
- ve != 0; paren_next (v, ve, e))
- {
- // See if the value contains the parameter symbol and, if so,
- // whether it is present in the bind array.
- //
- if ((find (v, ve, param_symbol) != 0 ||
- (param_symbol2 != '\0' && find (v, ve, param_symbol2) != 0)) &&
- bind_at (bi++, bind, bind_skip) == 0)
- continue;
-
- // Append the value.
- //
- if (i++ == 0)
- r += '(';
- else
- r += ", "; // Add the space for consistency with the fast path.
-
- r.append (v, ve - v);
- }
-
- r += ')';
- }
-
- // Trailer.
- //
- if (trailer_size != 0)
- {
- r += ' ';
- r.append (trailer_begin, trailer_size);
- }
-
-#ifdef LIBODB_TRACE_STATEMENT_PROCESSING
- if (r.size () != n)
- cerr << endl
- << "old: '" << s << "'" << endl << endl
- << "new: '" << r << "'" << endl << endl;
-#endif
- }
-
- void statement::
- process_update (string& r,
- const char* s,
- bind_type bind,
- size_t bind_size,
- size_t bind_skip,
- char param_symbol,
- char param_symbol2)
- {
- bool fast (true); // Fast case (if all present).
- for (size_t i (0); i != bind_size && fast; ++i)
- {
- if (bind_at (i, bind, bind_skip) == 0)
- fast = false;
- }
-
- // Fast path: just remove the "structure".
- //
-#ifndef LIBODB_DEBUG_STATEMENT_PROCESSING
- if (fast)
- {
- process_fast (s, r);
- return;
- }
-#endif
-
- // Scan the statement and store the positions of various parts.
- //
- size_t n (traits::length (s));
- const char* e (s + n);
-
- // Header.
- //
- const char* p (find (s, e, '\n'));
- assert (p != 0);
- size_t header_size (p - s);
- p++;
-
- // SET
- //
- bool empty (true); // Empty SET case.
- const char* set_begin (0);
- if (e - p > 4 && traits::compare (p, "SET\n", 4) == 0)
- {
- p += 4;
- set_begin = p;
-
- // Scan the SET list.
- //
- size_t bi (0);
- for (const char* pe (comma_begin (p, e)); pe != 0; comma_next (p, pe, e))
- {
- if (empty)
- {
- // We cannot be empty if we have a non-parameterized set expression,
- // e.g., UPDATE ... SET ver=ver+1 ... We also cannot be empty if
- // this expression is present in the bind array.
- //
- if ((find (p, pe, param_symbol) == 0 &&
- (param_symbol2 == '\0' || find (p, pe, param_symbol2) == 0)) ||
- bind_at (bi++, bind, bind_skip) != 0)
- empty = false;
- }
- }
- }
-
- // Empty case.
- //
- if (empty)
- {
- r.clear ();
-
-#ifdef LIBODB_TRACE_STATEMENT_PROCESSING
- if (n != 0)
- cerr << endl
- << "old: '" << s << "'" << endl << endl
- << "new: '" << r << "'" << endl << endl;
-#endif
-
- return;
- }
-
- // Trailer.
- //
- const char* trailer_begin (0);
- size_t trailer_size (0);
- if (e - p != 0)
- {
- trailer_begin = p;
- trailer_size = e - p;
- }
-
- // Assume the same size as the original. It can only shrink, and in
- // most cases only slightly. So this is a good approximation.
- //
- r.reserve (n);
- r.assign (s, header_size);
-
- // SET list.
- //
- {
- r += " SET ";
-
- size_t i (0), bi (0);
-
- for (const char* p (set_begin), *pe (comma_begin (p, e));
- pe != 0; comma_next (p, pe, e))
- {
- // See if the value contains the parameter symbol and, if so,
- // whether it is present in the bind array.
- //
- if ((find (p, pe, param_symbol) != 0 ||
- (param_symbol2 != '\0' && find (p, pe, param_symbol2) != 0)) &&
- bind_at (bi++, bind, bind_skip) == 0)
- continue;
-
- // Append the expression.
- //
- if (i++ != 0)
- r += ", "; // Add the space for consistency with the fast path.
-
- r.append (p, pe - p);
- }
- }
-
- // Trailer.
- //
- if (trailer_size != 0)
- {
- r += ' ';
- r.append (trailer_begin, trailer_size);
- }
-
-#ifdef LIBODB_TRACE_STATEMENT_PROCESSING
- if (r.size () != n)
- cerr << endl
- << "old: '" << s << "'" << endl << endl
- << "new: '" << r << "'" << endl << endl;
-#endif
- }
-
- void statement::
- process_select (string& r,
- const char* s,
- bind_type bind,
- size_t bind_size,
- size_t bind_skip,
- char quote_open,
- char quote_close,
-#ifndef LIBODB_DEBUG_STATEMENT_PROCESSING
- bool optimize,
-#else
- bool,
-#endif
- bool as)
- {
- bool empty (true); // Empty case (if none present).
- bool fast (true); // Fast case (if all present).
- for (size_t i (0); i != bind_size && (empty || fast); ++i)
- {
- if (bind_at (i, bind, bind_skip) != 0)
- empty = false;
- else
- fast = false;
- }
-
- // Empty.
- //
- if (empty)
- {
- r.clear ();
-
-#ifdef LIBODB_TRACE_STATEMENT_PROCESSING
- if (*s != '\0')
- cerr << endl
- << "old: '" << s << "'" << endl << endl
- << "new: '" << r << "'" << endl << endl;
-#endif
- return;
- }
-
- // Fast path: just remove the "structure".
- //
-#ifndef LIBODB_DEBUG_STATEMENT_PROCESSING
- if (fast && !optimize)
- {
- process_fast (s, r);
- return;
- }
-#endif
-
- // Scan the statement and store the positions of various parts.
- //
- size_t n (traits::length (s));
- const char* e (s + n);
-
- // Header.
- //
- const char* p (find (s, e, '\n'));
- assert (p != 0);
- size_t header_size (p - s);
- p++;
-
- // Column list.
- //
- const char* columns_begin (p);
- for (const char* ce (comma_begin (p, e)); ce != 0; comma_next (p, ce, e))
- ;
-
- // FROM.
- assert (traits::compare (p, "FROM ", 5) == 0);
- const char* from_begin (p);
- p = find (p, e, '\n'); // May not end with '\n'.
- if (p == 0)
- p = e;
- size_t from_size (p - from_begin);
- if (p != e)
- p++;
-
- // JOIN list.
- //
- const char* joins_begin (0), *joins_end (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, "JOIN ", 5, true))
- ;
-
- joins_end = (p != e ? p - 1 : p);
- }
-
-#ifndef LIBODB_DEBUG_STATEMENT_PROCESSING
- if (fast && joins_begin == 0)
- {
- // No JOINs to optimize so can still take the fast path.
- //
- process_fast (s, r);
- return;
- }
-#endif
-
- // Trailer (WHERE, ORDER BY, etc).
- //
- const char* trailer_begin (0);
- size_t trailer_size (0);
- if (e - p != 0)
- {
- trailer_begin = p;
- trailer_size = e - p;
- }
-
- // Assume the same size as the original. It can only shrink, and in
- // most cases only slightly. So this is a good approximation.
- //
- r.reserve (n);
- r.assign (s, header_size);
-
- // Column list.
- //
- {
- r += ' ';
-
- size_t i (0), bi (0);
-
- for (const char *c (columns_begin), *ce (comma_begin (c, e));
- ce != 0; comma_next (c, ce, e))
- {
- // See if the column is present in the bind array.
- //
- if (bind_at (bi++, bind, bind_skip) == 0)
- continue;
-
- // Append the column.
- //
- if (i++ != 0)
- r += ", "; // Add the space for consistency with the fast path.
-
- r.append (c, ce - c);
- }
- }
-
- // From.
- //
- r += ' ';
- r.append (from_begin, from_size);
-
- // JOIN list, pass 1.
- //
- size_t join_pos (0);
- if (joins_begin != 0)
- {
- // Fill in the JOIN "area" with spaces.
- //
- r.resize (r.size () + joins_end - joins_begin + 1, ' ');
- join_pos = r.size () + 1; // End of the last JOIN.
- }
-
- // Trailer.
- //
- if (trailer_size != 0)
- {
- r += ' ';
- r.append (trailer_begin, trailer_size);
- }
-
- // JOIN list, pass 2.
- //
- if (joins_begin != 0)
- {
- // Splice the JOINs into the pre-allocated area.
- //
- for (const char* je (joins_end), *j (newline_rbegin (je, joins_begin));
- j != 0; newline_rnext (j, je, joins_begin))
- {
- size_t n (je - j);
-
- // Get the alias or, if none used, the table name.
- //
- 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.
-
- // We may or may not have the AS keyword.
- //
- const char* alias_begin (0);
- size_t alias_size (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;
- p = find (p, je, ' '); // There might be no ON (CROSS JOIN).
- alias_size = (p != 0 ? p : je) - alias_begin;
- }
- else
- {
- // Just the table.
- //
- alias_begin = table_begin;
- alias_size = table_end - alias_begin;
- }
-
- // The alias must be quoted.
- //
- assert (*alias_begin == quote_open &&
- *(alias_begin + alias_size - 1) == quote_close);
-
- // We now need to see if the alias is used in either the SELECT
- // list, the WHERE conditions, or the ON condition of any of the
- // JOINs that we have already processed and decided to keep.
- //
- // 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 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
- // only a single identifer (column). This will catch cases like
- // [s].[t].[c] where [s] is also used as an alias or LEFT JOIN [t]
- // where [t] is also used as an alias in another JOIN.
- //
- bool found (false);
- for (size_t p (r.find (alias_begin, 0, alias_size));
- p != string::npos;
- p = r.find (alias_begin, p + alias_size, alias_size))
- {
- size_t e (p + alias_size);
-
- // If we are not a top-level qualifier or not a bottom-level,
- // then we are done (3 is for at least "[a]").
- //
- if ((p != 0 && r[p - 1] == '.') ||
- (e + 3 >= r.size () || (r[e] != '.' || r[e + 1] != quote_open)))
- continue;
-
- // The only way to distinguish the [a].[c] from FROM [a].[c] or
- // JOIN [a].[c] is by checking the prefix.
- //
- if ((p > 5 && r.compare (p - 5, 5, "FROM ") == 0) ||
- (p > 5 && r.compare (p - 5, 5, "JOIN ") == 0))
- continue;
-
- // Check that we are followed by a single identifier.
- //
- e = r.find (quote_close, e + 2);
- if (e == string::npos || (e + 1 != r.size () && r[e + 1] == '.'))
- continue;
-
- found = true;
- break;
- }
-
- join_pos -= n + 1; // Extra one for space.
- if (found)
- r.replace (join_pos, n, j, n);
- else
- r.erase (join_pos - 1, n + 1); // Extra one for space.
- }
- }
-
-#ifdef LIBODB_TRACE_STATEMENT_PROCESSING
- if (r.size () != n)
- cerr << endl
- << "old: '" << s << "'" << endl << endl
- << "new: '" << r << "'" << endl << endl;
-#endif
- }
-}