diff options
author | Karen Arutyunov <karen@codesynthesis.com> | 2024-01-24 16:53:38 +0300 |
---|---|---|
committer | Karen Arutyunov <karen@codesynthesis.com> | 2024-01-24 16:53:38 +0300 |
commit | 26e36b3a9d7b49d46ecfa69b447482251acba8ac (patch) | |
tree | 5436b7857fae9aee50d018ea0eef35a529fc03e4 /odb/statement-processing.cxx | |
parent | 0074faad1b27f3cd52a606c438e4f1375956d731 (diff) |
Turn libodb repository into package for muti-package repositorylibodb
Diffstat (limited to 'odb/statement-processing.cxx')
-rw-r--r-- | odb/statement-processing.cxx | 685 |
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 - } -} |