// file : common/statement/processing/driver.cxx // copyright : Copyright (c) 2009-2018 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file // Test internal statement processing machinery. // #include #include #include #include using namespace std; static bool insert (const char* stmt, const char* expected, const void* const* bind, size_t bind_size) { string r; odb::statement::process_insert ( r, stmt, bind, bind_size, sizeof (void*), '$'); return r == expected; } static bool update (const char* stmt, const char* expected, const void* const* bind, size_t bind_size) { string r; odb::statement::process_update ( r, stmt, bind, bind_size, sizeof (void*), '$'); return r == expected; } static bool select (const char* stmt, const char* expected, const void* const* bind, size_t bind_size) { string r; odb::statement::process_select ( r, stmt, bind, bind_size, sizeof (void*), '[', ']', true); return r == expected; } int main (int, char* argv[]) { // // INSERT // // Fast path. // { void* b[] = {argv, argv}; assert (insert ("INSERT INTO [foo]\n" "([a],\n[b])\n" "VALUES\n" "(DEFAULT,\n$1)", "INSERT INTO [foo] ([a], [b]) VALUES (DEFAULT, $1)", b, 2)); } // Empty via statement. // /* LIBODB_DEBUG_STATEMENT_PROCESSING { assert (insert ("INSERT INTO [foo]\n" "DEFAULT VALUES", "INSERT INTO [foo] DEFAULT VALUES", 0, 0)); } */ // Empty via bind. // { void* b[] = {0}; assert (insert ("INSERT INTO [foo]\n" "([a])\n" "VALUES\n" "($1)", "INSERT INTO [foo] DEFAULT VALUES", b, 1)); } // Empty with OUTPUT. // { void* b[] = {0, 0}; assert (insert ("INSERT INTO [foo]\n" "([a],\n[b])\n" "OUTPUT INSERTED.[id]\n" "VALUES\n" "($1,\n$2)", "INSERT INTO [foo] OUTPUT INSERTED.[id] DEFAULT VALUES", b, 2)); } // Empty with RETURNING. // { void* b[] = {0, 0, 0}; assert (insert ("INSERT INTO [foo]\n" "([a],\n[b],\n[c])\n" "VALUES\n" "($1,\n$1,\n$2)\n" "RETURNING [id]", "INSERT INTO [foo] DEFAULT VALUES RETURNING [id]", b, 3)); } // Empty via bind, but not values. // { void* b[] = {0}; assert (insert ("INSERT INTO [foo]\n" "([a],\n[b])\n" "VALUES\n" "(1,\n$1)", "INSERT INTO [foo] ([a]) VALUES (1)", b, 1)); } // Empty via bind, but not values. // { void* b[] = {0}; assert (insert ("INSERT INTO [foo]\n" "([a],\n[b],\n[c])\n" "VALUES\n" "(1,\n$1,\nDEFAULT)", "INSERT INTO [foo] ([a], [c]) VALUES (1, DEFAULT)", b, 1)); } // First not present. // { void* b[] = {0, argv, argv}; assert (insert ("INSERT INTO [foo]\n" "([a],\n[b],\n[c])\n" "VALUES\n" "($1,\n$2,\n$3)", "INSERT INTO [foo] ([b], [c]) VALUES ($2, $3)", b, 3)); } // Last not present. // { void* b[] = {argv, argv, 0}; assert (insert ("INSERT INTO [foo]\n" "([a],\n[b],\n[c])\n" "VALUES\n" "($1,\n$2,\n$3)", "INSERT INTO [foo] ([a], [b]) VALUES ($1, $2)", b, 3)); } // Middle not present. // { void* b[] = {argv, 0, argv}; assert (insert ("INSERT INTO [foo]\n" "([a],\n[b],\n[c])\n" "VALUES\n" "($1,\n$2,\n$3)", "INSERT INTO [foo] ([a], [c]) VALUES ($1, $3)", b, 3)); } // Multiple not present. // { void* b[] = {0, argv, 0, argv, 0}; assert (insert ("INSERT INTO [foo]\n" "([a],\n[b],\n[c],\n[d],\n[e])\n" "VALUES\n" "($1,\n$2,\n$3,\n$4,\n$5)", "INSERT INTO [foo] ([b], [d]) VALUES ($2, $4)", b, 5)); } // Not present and OUTPUT. // { void* b[] = {argv, 0, argv}; assert (insert ("INSERT INTO [foo]\n" "([a],\n[b],\n[c])\n" "OUTPUT INSERTED.[id]\n" "VALUES\n" "($1,\n$2,\n$3)", "INSERT INTO [foo] ([a], [c]) OUTPUT INSERTED.[id] " "VALUES ($1, $3)", b, 3)); } // Not present and RETURNING. // { void* b[] = {argv, 0, argv}; assert (insert ("INSERT INTO [foo]\n" "([a],\n[b],\n[c])\n" "VALUES\n" "($1,\n$2,\n$3)\n" "RETURNING [id]", "INSERT INTO [foo] ([a], [c]) VALUES ($1, $3) " "RETURNING [id]", b, 3)); } // Value expressions. // { void* b[] = {argv, argv, argv}; assert (insert ("INSERT INTO [foo]\n" "([a],\n[b],\n[c])\n" "VALUES\n" "($1,\nCAST($2, TEXT),\n$3)", "INSERT INTO [foo] ([a], [b], [c]) " "VALUES ($1, CAST($2, TEXT), $3)", b, 3)); } // // UPDATE // // Fast path. // { void* b[] = {argv, argv}; assert (update ("UPDATE [foo]\n" "SET\n" "ver=ver+1,\n[a]=$1\n" "WHERE [id]=$2", "UPDATE [foo] SET ver=ver+1, [a]=$1 WHERE [id]=$2", b, 2)); } // Empty via bind. // { void* b[] = {0, argv}; assert (update ("UPDATE [foo]\n" "SET\n" "[a]=$1\n" "WHERE [id]=$2", "", b, 2)); } // Empty via bind, but not values. // { void* b[] = {0, argv}; assert (update ("UPDATE [foo]\n" "SET\n" "ver=ver+1,\n[a]=$1\n" "WHERE [id]=$2", "UPDATE [foo] SET ver=ver+1 WHERE [id]=$2", b, 2)); } // First not present. // { void* b[] = {0, argv, argv, argv}; assert (update ("UPDATE [foo]\n" "SET\n" "[a]=$1,\n" "[b]=$2,\n" "[c]=$3\n" "WHERE [id]=$4", "UPDATE [foo] SET [b]=$2, [c]=$3 WHERE [id]=$4", b, 4)); } // Last not present. // { void* b[] = {argv, argv, 0, argv}; assert (update ("UPDATE [foo]\n" "SET\n" "[a]=$1,\n" "[b]=$2,\n" "[c]=$3\n" "WHERE [id]=$4", "UPDATE [foo] SET [a]=$1, [b]=$2 WHERE [id]=$4", b, 4)); } // Middle not present. // { void* b[] = {argv, 0, argv, argv}; assert (update ("UPDATE [foo]\n" "SET\n" "[a]=$1,\n" "[b]=$2,\n" "[c]=$3\n" "WHERE [id]=$4", "UPDATE [foo] SET [a]=$1, [c]=$3 WHERE [id]=$4", b, 4)); } // Multiple not present. // { void* b[] = {0, argv, 0, argv, argv}; assert (update ("UPDATE [foo]\n" "SET\n" "[a]=$1,\n" "[b]=$2,\n" "[c]=$3,\n" "[d]=$4\n" "WHERE [id]=$5", "UPDATE [foo] SET [b]=$2, [d]=$4 WHERE [id]=$5", b, 5)); } // Not present and OUTPUT. // { void* b[] = {argv, 0, argv, argv}; assert (update ("UPDATE [foo]\n" "SET\n" "[a]=$1,\n" "[b]=$2,\n" "[c]=$3\n" "OUTPUT INSERTED.[ver] " "WHERE [id]=$4", "UPDATE [foo] SET [a]=$1, [c]=$3 OUTPUT INSERTED.[ver] " "WHERE [id]=$4", b, 4)); } // Value expressions. // { void* b[] = {argv, argv, argv, argv}; assert (update ("UPDATE [foo]\n" "SET\n" "[a]=$1,\n" "[b]=CAST($2, TEXT),\n" "[c]=$3\n" "WHERE [id]=$4", "UPDATE [foo] SET [a]=$1, [b]=CAST($2, TEXT), [c]=$3 " "WHERE [id]=$4", b, 4)); } // No OUTPUT/WHERE clause. // { void* b[] = {argv, 0, argv}; assert (update ("UPDATE [foo]\n" "SET\n" "[a]=$1,\n" "[b]=$2,\n" "[c]=$3", "UPDATE [foo] SET [a]=$1, [c]=$3", b, 4)); } // // SELECT // // Empty. // { void* b[] = {0, 0, 0}; assert (select ("SELECT\n" "[a].[x],\n" "[t].[y],\n" "[t].[z]\n" "FROM [t]\n" "LEFT JOIN [t1] AS [a] ON [a].[id]=[t].[id]\n" "WHERE [t].[id]=$1", "", b, 3)); } // Fast path. // { void* b[] = {argv, argv}; assert (select ("SELECT\n" "[s].[t].[x],\n" "[a].[y]\n" "FROM [s].[t]\n" "LEFT JOIN [t1] AS [a] ON [a].[id]=[s].[t].[id]\n" "WHERE [s].[t].[id]=$1", "SELECT [s].[t].[x], [a].[y] FROM [s].[t] " "LEFT JOIN [t1] AS [a] ON [a].[id]=[s].[t].[id] " "WHERE [s].[t].[id]=$1", b, 2)); } // First not present. // { void* b[] = {0, argv, argv}; assert (select ("SELECT\n" "[a].[x],\n" "[t].[y],\n" "[t].[z]\n" "FROM [t]\n" "LEFT JOIN [t1] AS [a] ON [a].[id]=[t].[id]\n" "WHERE [t].[id]=$1", "SELECT [t].[y], [t].[z] FROM [t] WHERE [t].[id]=$1", b, 3)); } // Last not present. // { void* b[] = {argv, argv, 0}; assert (select ("SELECT\n" "[t].[x],\n" "[t].[y],\n" "[a].[z]\n" "FROM [t]\n" "LEFT JOIN [t1] AS [a] ON [a].[id]=[t].[id]\n" "WHERE [t].[id]=$1", "SELECT [t].[x], [t].[y] FROM [t] WHERE [t].[id]=$1", b, 3)); } // Middle not present. // { void* b[] = {argv, 0, argv}; assert (select ("SELECT\n" "[t].[x],\n" "[a].[y],\n" "[t].[z]\n" "FROM [t]\n" "LEFT JOIN [t1] AS [a] ON [a].[id]=[t].[id]\n" "WHERE [t].[id]=$1", "SELECT [t].[x], [t].[z] FROM [t] WHERE [t].[id]=$1", b, 3)); } // Multiple not present. // { void* b[] = {0, argv, 0, argv}; assert (select ("SELECT\n" "[a1].[w],\n" "[t].[x],\n" "[a2].[y],\n" "[a3].[z]\n" "FROM [t]\n" "LEFT JOIN [t1] AS [a1] ON [a1].[id]=[t].[id]\n" "LEFT JOIN [t2] AS [a2] ON [a2].[id]=[t].[id]\n" "LEFT JOIN [t3] AS [a3] ON [a3].[id]=[t].[id]\n" "WHERE [t].[id]=$1", "SELECT [t].[x], [a3].[z] FROM [t] " "LEFT JOIN [t3] AS [a3] ON [a3].[id]=[t].[id] " "WHERE [t].[id]=$1", b, 4)); } // Column expression. // { void* b[] = {argv, argv, 0}; assert (select ("SELECT\n" "[t].[x],\n" "CAST([a].[y], TEXT),\n" "[t].[z]\n" "FROM [t]\n" "LEFT JOIN [t1] AS [a] ON [a].[id]=[t].[id]\n" "WHERE [t].[id]=$1", "SELECT [t].[x], CAST([a].[y], TEXT) FROM [t] " "LEFT JOIN [t1] AS [a] ON [a].[id]=[t].[id] " "WHERE [t].[id]=$1", b, 3)); } // No WHERE. // { void* b[] = {argv, 0, argv}; assert (select ("SELECT\n" "[t].[x],\n" "[t].[y],\n" "[t].[z]\n" "FROM [t]", "SELECT [t].[x], [t].[z] FROM [t]", b, 3)); } // JOIN without WHERE. // { void* b[] = {argv, 0, argv}; assert (select ("SELECT\n" "[t].[x],\n" "[a].[y],\n" "[t].[z]\n" "FROM [t]\n" "LEFT JOIN [t1] AS [a] ON [a].[id]=[t].[id]", "SELECT [t].[x], [t].[z] FROM [t]", b, 3)); } // JOIN presence because of WHERE. // { void* b[] = {argv, 0, argv}; assert (select ("SELECT\n" "[t].[x],\n" "[a].[y],\n" "[t].[z]\n" "FROM [t]\n" "LEFT JOIN [t1] AS [a] ON [a].[id]=[t].[id]\n" "WHERE [t].[id]=$1 AND [a].[id]=$2", "SELECT [t].[x], [t].[z] FROM [t] " "LEFT JOIN [t1] AS [a] ON [a].[id]=[t].[id] " "WHERE [t].[id]=$1 AND [a].[id]=$2", b, 3)); } // JOIN presence because of dependent JOIN. // { void* b[] = {argv, argv, argv}; assert (select ("SELECT\n" "[t].[x],\n" "[a_b].[y],\n" "[t].[z]\n" "FROM [t]\n" "LEFT JOIN [d] AS [a_d] ON [a_d].[id]=[t].[id]\n" "LEFT JOIN [b] AS [a_b] ON [a_b].[id]=[a_d].[id]\n" "WHERE [t].[id]=$1", "SELECT [t].[x], [a_b].[y], [t].[z] FROM [t] " "LEFT JOIN [d] AS [a_d] ON [a_d].[id]=[t].[id] " "LEFT JOIN [b] AS [a_b] ON [a_b].[id]=[a_d].[id] " "WHERE [t].[id]=$1", b, 3)); } // JOIN without alias and with schema. // { void* b[] = {argv, argv, argv}; assert (select ("SELECT\n" "[t].[x],\n" "[s].[t1].[y],\n" "[t2].[z]\n" "FROM [t]\n" "LEFT JOIN [s].[t1] ON [s].[t1].[id]=[t].[id]\n" "LEFT JOIN [t2] ON [t2].[id]=[t].[id]\n" "WHERE [t].[id]=$1", "SELECT [t].[x], [s].[t1].[y], [t2].[z] FROM [t] " "LEFT JOIN [s].[t1] ON [s].[t1].[id]=[t].[id] " "LEFT JOIN [t2] ON [t2].[id]=[t].[id] " "WHERE [t].[id]=$1", b, 3)); } // JOIN alias top-level qualifer test. // { void* b[] = {argv, 0}; assert (select ("SELECT\n" "[s].[a].[x],\n" "[a].[y]\n" "FROM [s].[a]\n" "LEFT JOIN [t1] AS [a] ON [a].[id]=[s].[a].[id]\n" "WHERE [s].[a].[id]=$1", "SELECT [s].[a].[x] FROM [s].[a] WHERE [s].[a].[id]=$1", b, 2)); } // JOIN alias bottom-level qualifer test (FROM case). // { void* b[] = {argv, 0}; assert (select ("SELECT\n" "[a].[t].[x],\n" "[a].[y]\n" "FROM [a].[t]\n" "LEFT JOIN [t1] AS [a] ON [a].[id]=[a].[t].[id]\n" "WHERE [a].[t].[id]=$1", "SELECT [a].[t].[x] FROM [a].[t] WHERE [a].[t].[id]=$1", b, 2)); } // JOIN alias bottom-level qualifer test (LEFT JOIN case). // { void* b[] = {0, argv}; assert (select ("SELECT\n" "[a].[y],\n" "[a].[t2].[x]\n" "FROM [t]\n" "LEFT JOIN [t1] AS [a] ON [a].[id]=[t].[id]\n" "LEFT JOIN [a].[t2] ON [a].[t2].[id]=[t].[id]\n" "WHERE [t].[id]=$1", "SELECT [a].[t2].[x] FROM [t] " "LEFT JOIN [a].[t2] ON [a].[t2].[id]=[t].[id] " "WHERE [t].[id]=$1", b, 2)); } }