From c7da18798fd2ec4953db3b47ca680a37348fa132 Mon Sep 17 00:00:00 2001 From: Egor Pugin Date: Fri, 20 Apr 2018 17:11:40 +0300 Subject: [PATCH 01/25] Add simplified sqlite2cpp generator script that uses sqlite3 schema parsing. --- scripts/sqlite2cpp.py | 200 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 scripts/sqlite2cpp.py diff --git a/scripts/sqlite2cpp.py b/scripts/sqlite2cpp.py new file mode 100644 index 00000000..3a9696dc --- /dev/null +++ b/scripts/sqlite2cpp.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python3 + +## + # Copyright (c) 2013-2015, Roland Bock + # Copyright (c) 2018, Egor Pugin + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without modification, + # are permitted provided that the following conditions are met: + # + # * Redistributions of source code must retain the above copyright notice, + # this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright notice, + # this list of conditions and the following disclaimer in the documentation + # and/or other materials provided with the distribution. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # OF THE POSSIBILITY OF SUCH DAMAGE. + ## + +import argparse +import os +import re +import sqlite3 +import sys + +INCLUDE = 'sqlpp11' +NAMESPACE = 'sqlpp' + +# map sqlite3 types +types = { + 'integer': 'integer', + 'text': 'text', + 'blob': 'blob', + 'real': 'floating_point', +} + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('ddl', help='path to ddl') + parser.add_argument('target', help='path to target') + parser.add_argument('namespace', help='namespace') + args = parser.parse_args() + + pathToHeader = args.target + '.h' + + # execute schema scripts + conn = sqlite3.connect(':memory:') + conn.executescript(open(args.ddl).read()) + + # set vars + toClassName = class_name_naming_func + toMemberName = member_name_naming_func + DataTypeError = False + + header = open(pathToHeader, 'w') + namespace = args.namespace + nsList = namespace.split('::') + + # start printing + print('// generated by ' + ' '.join(sys.argv), file=header) + print('#ifndef '+get_include_guard_name(namespace, pathToHeader), file=header) + print('#define '+get_include_guard_name(namespace, pathToHeader), file=header) + print('', file=header) + print('#include <' + INCLUDE + '/table.h>', file=header) + print('#include <' + INCLUDE + '/data_types.h>', file=header) + print('#include <' + INCLUDE + '/char_sequence.h>', file=header) + print('', file=header) + for ns in nsList: + print('namespace ' + ns, file=header) + print('{', file=header) + + cursor = conn.cursor() + cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") + tables = cursor.fetchall() + for table_name in tables: + table_name = table_name[0] + + if table_name.startswith('sqlite_'): + continue + + sqlTableName = table_name + tableClass = toClassName(sqlTableName) + tableMember = toMemberName(sqlTableName) + tableNamespace = tableClass + '_' + tableTemplateParameters = tableClass + print(' namespace ' + tableNamespace, file=header) + print(' {', file=header) + + columns = cursor.execute("PRAGMA table_info('%s')" % table_name).fetchall() + for column in columns: + sqlColumnName = column[1] + columnClass = toClassName(sqlColumnName) + tableTemplateParameters += ',\n ' + tableNamespace + '::' + columnClass + columnMember = toMemberName(sqlColumnName) + sqlColumnType = column[2].lower() + print(' struct ' + columnClass, file=header) + print(' {', file=header) + print(' struct _alias_t', file=header) + print(' {', file=header) + print(' static constexpr const char _literal[] = "' + escape_if_reserved(sqlColumnName) + '";', file=header) + print(' using _name_t = sqlpp::make_char_sequence;', file=header) + print(' template', file=header) + print(' struct _member_t', file=header) + print(' {', file=header) + print(' T ' + columnMember + ';', file=header) + print(' T& operator()() { return ' + columnMember + '; }', file=header) + print(' const T& operator()() const { return ' + columnMember + '; }', file=header) + print(' };', file=header) + print(' };', file=header) + try: + traitslist = [NAMESPACE + '::' + types[sqlColumnType]] + except KeyError as e: + print ('Error: datatype "' + sqlColumnType + '"" is not supported.') + DataTypeError = True + requireInsert = True + hasAutoValue = sqlColumnName == 'id' + if hasAutoValue: + traitslist.append(NAMESPACE + '::tag::must_not_insert') + traitslist.append(NAMESPACE + '::tag::must_not_update') + requireInsert = False + if column[3] == '0': + traitslist.append(NAMESPACE + '::tag::can_be_null') + requireInsert = False + if column[4]: + requireInsert = False + if requireInsert: + traitslist.append(NAMESPACE + '::tag::require_insert') + print(' using _traits = ' + NAMESPACE + '::make_traits<' + ', '.join(traitslist) + '>;', file=header) + print(' };', file=header) + + + print(' } // namespace ' + tableNamespace, file=header) + print('', file=header) + + print(' struct ' + tableClass + ': ' + NAMESPACE + '::table_t<' + tableTemplateParameters + '>', file=header) + print(' {', file=header) + print(' struct _alias_t', file=header) + print(' {', file=header) + print(' static constexpr const char _literal[] = "' + sqlTableName + '";', file=header) + print(' using _name_t = sqlpp::make_char_sequence;', file=header) + print(' template', file=header) + print(' struct _member_t', file=header) + print(' {', file=header) + print(' T ' + tableMember + ';', file=header) + print(' T& operator()() { return ' + tableMember + '; }', file=header) + print(' const T& operator()() const { return ' + tableMember + '; }', file=header) + print(' };', file=header) + print(' };', file=header) + print(' };', file=header) + + + for ns in nsList: + print('} // namespace ' + ns, file=header) + print('#endif', file=header) + + if (DataTypeError): + print("Error: unsupported datatypes." ) + print("Possible solutions:") + print("A) Implement this datatype (examples: sqlpp11/data_types)" ) + print("B) Extend/upgrade ddl2cpp (edit types map)" ) + print("C) Raise an issue on github" ) + sys.exit(10) #return non-zero error code, we might need it for automation + +def get_include_guard_name(namespace, inputfile): + val = re.sub("[^A-Za-z0-9]+", "_", namespace + '_' + os.path.basename(inputfile)) + return val.upper() + +def repl_camel_case_func(m): + if m.group(1) == '_': + return m.group(2).upper() + else: + return m.group(1) + m.group(2).upper() + +def class_name_naming_func(s): + return re.sub("(^|\s|[_0-9])(\S)", repl_camel_case_func, s) + +def member_name_naming_func(s): + return re.sub("(\s|_|[0-9])(\S)", repl_camel_case_func, s) + +def escape_if_reserved(name): + reserved_names = [ + 'GROUP', + 'ORDER', + ] + if name.upper() in reserved_names: + return '!{}'.format(name) + return name + +if __name__ == '__main__': + main() + sys.exit(0) From c9007a7098fd891c742550ea58469a1b59238f25 Mon Sep 17 00:00:00 2001 From: Egor Pugin Date: Fri, 20 Apr 2018 17:13:24 +0300 Subject: [PATCH 02/25] Remove blank line. --- scripts/sqlite2cpp.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/sqlite2cpp.py b/scripts/sqlite2cpp.py index 3a9696dc..652a1fa2 100644 --- a/scripts/sqlite2cpp.py +++ b/scripts/sqlite2cpp.py @@ -137,7 +137,6 @@ def main(): print(' using _traits = ' + NAMESPACE + '::make_traits<' + ', '.join(traitslist) + '>;', file=header) print(' };', file=header) - print(' } // namespace ' + tableNamespace, file=header) print('', file=header) From 9db9fed69711b0e443c432827ad3ef481f4bd593 Mon Sep 17 00:00:00 2001 From: Egor Pugin Date: Fri, 20 Apr 2018 17:15:27 +0300 Subject: [PATCH 03/25] Fix program desc. --- scripts/sqlite2cpp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/sqlite2cpp.py b/scripts/sqlite2cpp.py index 652a1fa2..71c5c5a8 100644 --- a/scripts/sqlite2cpp.py +++ b/scripts/sqlite2cpp.py @@ -44,7 +44,7 @@ types = { } def main(): - parser = argparse.ArgumentParser(description='Process some integers.') + parser = argparse.ArgumentParser(description='sqlpp11 cpp schema generator') parser.add_argument('ddl', help='path to ddl') parser.add_argument('target', help='path to target') parser.add_argument('namespace', help='namespace') From 3faa8fa8bc83d3b9053b04a1c6091737e7e237b2 Mon Sep 17 00:00:00 2001 From: Sylvain Joubert Date: Mon, 13 Aug 2018 12:59:30 +0200 Subject: [PATCH 04/25] Fix typos in function's tests --- tests/Function.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/Function.cpp b/tests/Function.cpp index 1b24e77f..dba35ab3 100644 --- a/tests/Function.cpp +++ b/tests/Function.cpp @@ -352,9 +352,9 @@ int Function(int, char* []) using TT = decltype(sqlpp::value("cheesecake")); static_assert(not sqlpp::is_selectable_t::value, "type requirement"); static_assert(sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_selectable_t::value, "type requirement"); - static_assert(sqlpp::is_integral_t::value, "type requirement"); static_assert(not sqlpp::is_selectable_t::value, "type requirement"); + static_assert(sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_selectable_t::value, "type requirement"); static_assert(sqlpp::is_floating_point_t::value, "type requirement"); static_assert(not sqlpp::is_selectable_t::value, "type requirement"); static_assert(sqlpp::is_text_t::value, "type requirement"); @@ -368,9 +368,9 @@ int Function(int, char* []) using TT = decltype(flatten(t.beta, db)); static_assert(not sqlpp::is_selectable_t::value, "type requirement"); static_assert(sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_selectable_t::value, "type requirement"); - static_assert(sqlpp::is_integral_t::value, "type requirement"); static_assert(not sqlpp::is_selectable_t::value, "type requirement"); + static_assert(sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_selectable_t::value, "type requirement"); static_assert(sqlpp::is_floating_point_t::value, "type requirement"); static_assert(not sqlpp::is_selectable_t::value, "type requirement"); static_assert(sqlpp::is_text_t::value, "type requirement"); @@ -392,9 +392,9 @@ int Function(int, char* []) static_assert(std::is_same::value, "type_requirement"); static_assert(not sqlpp::is_selectable_t::value, "type requirement"); static_assert(sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_selectable_t::value, "type requirement"); - static_assert(sqlpp::is_integral_t::value, "type requirement"); static_assert(not sqlpp::is_selectable_t::value, "type requirement"); + static_assert(sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_selectable_t::value, "type requirement"); static_assert(sqlpp::is_floating_point_t::value, "type requirement"); static_assert(not sqlpp::is_selectable_t::value, "type requirement"); static_assert(sqlpp::is_text_t::value, "type requirement"); @@ -411,9 +411,9 @@ int Function(int, char* []) static_assert(sqlpp::is_boolean_t::value, "type requirement"); static_assert(sqlpp::is_selectable_t::value, "type requirement"); static_assert(sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_selectable_t::value, "type requirement"); - static_assert(sqlpp::is_integral_t::value, "type requirement"); static_assert(not sqlpp::is_selectable_t::value, "type requirement"); + static_assert(sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_selectable_t::value, "type requirement"); static_assert(sqlpp::is_floating_point_t::value, "type requirement"); static_assert(not sqlpp::is_selectable_t::value, "type requirement"); static_assert(sqlpp::is_text_t::value, "type requirement"); From 114b9ab77a2ae46c641f13467f3213a007b88fe4 Mon Sep 17 00:00:00 2001 From: Sylvain Joubert Date: Mon, 13 Aug 2018 21:31:09 +0200 Subject: [PATCH 05/25] Add support of value_or_null in multi-insert --- include/sqlpp11/insert_value.h | 7 +++++++ tests/Insert.cpp | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/include/sqlpp11/insert_value.h b/include/sqlpp11/insert_value.h index e78c9043..d84b9f8f 100644 --- a/include/sqlpp11/insert_value.h +++ b/include/sqlpp11/insert_value.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -64,6 +65,7 @@ namespace sqlpp using _pure_value_t = typename value_type_of::_cpp_value_type; using _wrapped_value_t = wrap_operand_t<_pure_value_t>; using _tvin_t = tvin_t<_wrapped_value_t>; + using _value_or_null_t = value_or_null_t; insert_value_t(rhs_wrap_t<_wrapped_value_t, _trivial_value_is_null> rhs) : _is_null(rhs._is_null()), _is_default(rhs._is_default()), _value(rhs._expr._t) @@ -85,6 +87,11 @@ namespace sqlpp { } + insert_value_t(const rhs_wrap_t<_value_or_null_t, _trivial_value_is_null>& rhs) + : _is_null(rhs._expr._is_null), _is_default(false), _value{rhs._expr._value} + { + } + insert_value_t(const insert_value_t&) = default; insert_value_t(insert_value_t&&) = default; insert_value_t& operator=(const insert_value_t&) = default; diff --git a/tests/Insert.cpp b/tests/Insert.cpp index 6097b450..a364fdce 100644 --- a/tests/Insert.cpp +++ b/tests/Insert.cpp @@ -54,6 +54,8 @@ int Insert(int, char*[]) db(insert_into(t).default_values()); db(insert_into(t).set(t.gamma = true, t.beta = "kirschauflauf")); + db(insert_into(t).set(t.gamma = sqlpp::default_value, t.beta = sqlpp::value_or_null("pie"), + t.delta = sqlpp::value_or_null(sqlpp::null))); serialize(insert_into(t).default_values(), printer).str(); @@ -64,6 +66,9 @@ int Insert(int, char*[]) multi_insert.values.add(t.gamma = true, t.beta = "cheesecake", t.delta = 1); multi_insert.values.add(t.gamma = sqlpp::default_value, t.beta = sqlpp::default_value, t.delta = sqlpp::default_value); + multi_insert.values.add(t.gamma = sqlpp::value_or_null(true), + t.beta = sqlpp::value_or_null("pie"), + t.delta = sqlpp::value_or_null(sqlpp::null)); auto i = dynamic_insert_into(db, t).dynamic_set(); i.insert_list.add(t.beta = "kirschauflauf"); printer.reset(); From 4c53ffcb3f1be1942a259e8f588d327714277500 Mon Sep 17 00:00:00 2001 From: Aaron Bishop Date: Tue, 25 Sep 2018 08:43:10 -0400 Subject: [PATCH 06/25] Add option to ddl2cpp to enable splitting tables into individual header files --- scripts/ddl2cpp | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/scripts/ddl2cpp b/scripts/ddl2cpp index 1649b78e..dc679d5f 100755 --- a/scripts/ddl2cpp +++ b/scripts/ddl2cpp @@ -85,6 +85,26 @@ def usage(optionalArgs = {}): Usage: ddl2cpp \n\ ddl2cpp -help') +def beginHeader(pathToHeader, nsList): + header = open(pathToHeader, 'w') + print('// generated by ' + ' '.join(sys.argv), file=header) + print('#ifndef '+get_include_guard_name(namespace, pathToHeader), file=header) + print('#define '+get_include_guard_name(namespace, pathToHeader), file=header) + print('', file=header) + print('#include <' + INCLUDE + '/table.h>', file=header) + print('#include <' + INCLUDE + '/data_types.h>', file=header) + print('#include <' + INCLUDE + '/char_sequence.h>', file=header) + print('', file=header) + for ns in nsList: + print('namespace ' + ns, file=header) + print('{', file=header) + return header + +def endHeader(header, nsList): + for ns in nsList: + print('} // namespace ' + ns, file=header) + print('#endif', file=header) + header.close() def help_message(): arg_string = '\n' @@ -118,6 +138,7 @@ optionalArgs = { '-warn-on-parse': "warn about unusable headers, but continue", # warnOnParse = True '-auto-id': "Assume column 'id' to have an automatic value as if AUTO_INCREMENT was specified (e.g. implicit for SQLite ROWID)", # autoId = True '-identity-naming': "Use table and column names from the ddl (defaults to UpperCamelCase for tables and lowerCamelCase for columns", # identityNaming = True + '-split-tables': "Make a header for each table name, using target as a directory", # splitTables = True '-help': "show this help" } @@ -135,6 +156,7 @@ warnOnParse = False parseError = "Parsing error, possible reason: can't parse default value for a field" autoId = False identityNaming = False +splitTables = False if len(sys.argv) >= 4: @@ -155,7 +177,7 @@ if identityNaming: pathToDdl = sys.argv[firstPositional] -pathToHeader = sys.argv[firstPositional + 1] + '.h' +pathToHeader = sys.argv[firstPositional + 1] + ('/' if splitTables else '.h') namespace = sys.argv[firstPositional + 2] @@ -297,21 +319,14 @@ def escape_if_reserved(name): # PROCESS DDL tableCreations = ddl.parseFile(pathToDdl) -header = open(pathToHeader, 'w') -print('// generated by ' + ' '.join(sys.argv), file=header) -print('#ifndef '+get_include_guard_name(namespace, pathToHeader), file=header) -print('#define '+get_include_guard_name(namespace, pathToHeader), file=header) -print('', file=header) -print('#include <' + INCLUDE + '/table.h>', file=header) -print('#include <' + INCLUDE + '/data_types.h>', file=header) -print('#include <' + INCLUDE + '/char_sequence.h>', file=header) -print('', file=header) -for ns in nsList: - print('namespace ' + ns, file=header) - print('{', file=header) +header = 0 +if not splitTables: + header = beginHeader(pathToHeader, nsList) DataTypeError = False for create in tableCreations: sqlTableName = create.tableName + if splitTables: + header = beginHeader(pathToHeader + sqlTableName + '.h', nsList) tableClass = toClassName(sqlTableName) tableMember = toMemberName(sqlTableName) tableNamespace = tableClass + '_' @@ -385,10 +400,11 @@ for create in tableCreations: print(' };', file=header) print(' };', file=header) print(' };', file=header) + if splitTables: + endHeader(header, nsList) -for ns in nsList: - print('} // namespace ' + ns, file=header) -print('#endif', file=header) +if not splitTables: + endHeader(header, nsList) if (DataTypeError): print("Error: unsupported datatypes." ) print("Possible solutions:") From da5cf192e951c8d276d45a9960503a3d5d02e440 Mon Sep 17 00:00:00 2001 From: fjkfwz Date: Fri, 26 Oct 2018 19:30:09 +0800 Subject: [PATCH 07/25] Fix blob field display --- include/sqlpp11/data_types/blob/result_field.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/sqlpp11/data_types/blob/result_field.h b/include/sqlpp11/data_types/blob/result_field.h index 0b610c5a..b6fadccb 100644 --- a/include/sqlpp11/data_types/blob/result_field.h +++ b/include/sqlpp11/data_types/blob/result_field.h @@ -33,6 +33,7 @@ #include #include #include +#include namespace sqlpp { @@ -76,7 +77,9 @@ namespace sqlpp } else { - return os << e.value(); + std::vector value = e.value(); + std::string value_str(value.begin(), value.end()); + return os << value_str; } } } // namespace sqlpp From 9de56a748c2b9bbde5ada095dcf1d79bf64af33f Mon Sep 17 00:00:00 2001 From: Egor Pugin Date: Thu, 6 Dec 2018 22:05:24 +0300 Subject: [PATCH 08/25] Add explicit greater condition. --- include/sqlpp11/table.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sqlpp11/table.h b/include/sqlpp11/table.h index 17a80836..cf0c9a3f 100644 --- a/include/sqlpp11/table.h +++ b/include/sqlpp11/table.h @@ -52,7 +52,7 @@ namespace sqlpp using _nodes = detail::type_vector<>; using _provided_tables = detail::type_set; - static_assert(sizeof...(ColumnSpec), "at least one column required per table"); + static_assert(sizeof...(ColumnSpec) > 0, "at least one column required per table"); using _required_insert_columns = typename detail::make_type_set_if...>::type; using _column_tuple_t = std::tuple...>; From dd73319bcf80a31b5f9636a6c4fd8fa16ddd0604 Mon Sep 17 00:00:00 2001 From: rbock Date: Fri, 7 Dec 2018 09:42:43 +0100 Subject: [PATCH 09/25] Add boolean expression test --- tests/BooleanExpression.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/BooleanExpression.cpp b/tests/BooleanExpression.cpp index da9c14bb..2e84c5d8 100644 --- a/tests/BooleanExpression.cpp +++ b/tests/BooleanExpression.cpp @@ -28,12 +28,13 @@ #include "MockDb.h" #include -int BooleanExpression(int, char* []) +int BooleanExpression(int, char*[]) { MockDb db = {}; const auto t = test::TabBar{}; auto x = boolean_expression(db, not(t.alpha == 7)); + x = sqlpp::boolean_expression(db, true); x = sqlpp::boolean_expression(t.beta.like("%cheesecake")); x = x and boolean_expression(db, t.gamma); From 7e2e1abbfcdadbd2fc3e3adb84873973920c0d60 Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 24 Dec 2018 17:32:16 +0100 Subject: [PATCH 10/25] Add example for MYSQL's ON DUPLICATE KEY UPDATE --- tests/CustomQuery.cpp | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/tests/CustomQuery.cpp b/tests/CustomQuery.cpp index 94af9bff..6a15b90d 100644 --- a/tests/CustomQuery.cpp +++ b/tests/CustomQuery.cpp @@ -29,7 +29,35 @@ #include #include -int CustomQuery(int, char* []) +namespace +{ + struct on_duplicate_key_update + { + std::string _serialized; + + template + on_duplicate_key_update(Db&, Assignment assignment) + { + typename Db::_serializer_context_t context; + _serialized = " ON DUPLICATE KEY UPDATE " + serialize(assignment, context).str(); + } + + template + auto operator()(Db&, Assignment assignment) -> on_duplicate_key_update& + { + typename Db::_serializer_context_t context; + _serialized += ", " + serialize(assignment, context).str(); + return *this; + } + + auto get() const -> sqlpp::verbatim_t<::sqlpp::no_value_t> + { + return ::sqlpp::verbatim(_serialized); + } + }; +} // namespace + +int CustomQuery(int, char*[]) { MockDb db = {}; MockDb::_serializer_context_t printer = {}; @@ -61,6 +89,10 @@ int CustomQuery(int, char* []) db(custom_query(sqlpp::insert(), sqlpp::verbatim(" OR IGNORE"), into(t), insert_set(t.beta = "sample", t.gamma = true))); + // Create a MYSQL style custom "insert on duplicate update" + db(custom_query(sqlpp::insert_into(t).set(t.beta = "sample", t.gamma = true), + on_duplicate_key_update(db, t.beta = "sample")(db, t.gamma = false).get())); + // A custom (select ... into) with adjusted return type // The first argument with a return type is the select, but the custom query is really an insert. Thus, we tell it so. printer.reset(); From 052dbe10b2a675f39a057516403054f722639923 Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 24 Dec 2018 17:44:17 +0100 Subject: [PATCH 11/25] Re-added accidentally removed `real` type to ddl2cpp --- scripts/ddl2cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/ddl2cpp b/scripts/ddl2cpp index dc679d5f..133aea64 100755 --- a/scripts/ddl2cpp +++ b/scripts/ddl2cpp @@ -268,6 +268,7 @@ types = { 'float8': 'floating_point', # PostgreSQL 'float': 'floating_point', 'float4': 'floating_point', # PostgreSQL + 'real': 'floating_point', 'numeric': 'floating_point', # PostgreSQL 'date': 'day_point', 'datetime': 'time_point', From cf02a444d727d1d2cad52fb3657d0c90873abd2e Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 23 Jan 2019 15:34:47 +0100 Subject: [PATCH 12/25] Add custom query insert example --- tests/CustomQuery.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/CustomQuery.cpp b/tests/CustomQuery.cpp index 6a15b90d..35d2bc7f 100644 --- a/tests/CustomQuery.cpp +++ b/tests/CustomQuery.cpp @@ -101,6 +101,10 @@ int CustomQuery(int, char*[]) auto i = db(c); static_assert(std::is_integral::value, "insert yields an integral value"); + auto d = custom_query(sqlpp::verbatim("INSERT INTO tab_sample VALUES()")).with_result_type_of(sqlpp::insert()); + auto j = db(d); + static_assert(std::is_integral::value, "insert yields an integral value"); + for (const auto& row : db(custom_query(sqlpp::verbatim("PRAGMA user_version")).with_result_type_of(select(all_of(t))))) { From ac3a8290ffac0f694e6c0a9930c11dd24f71e893 Mon Sep 17 00:00:00 2001 From: Daniel Evers Date: Thu, 24 Jan 2019 15:08:43 +0100 Subject: [PATCH 13/25] support for std::string_view when using C++17 --- include/sqlpp11/data_types/text/operand.h | 13 +++++++++++++ include/sqlpp11/data_types/text/wrap_operand.h | 11 ++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/include/sqlpp11/data_types/text/operand.h b/include/sqlpp11/data_types/text/operand.h index fc2fda1c..1bf169be 100644 --- a/include/sqlpp11/data_types/text/operand.h +++ b/include/sqlpp11/data_types/text/operand.h @@ -29,6 +29,9 @@ #include #include +#if __cplusplus >= 201703L +#include +#endif #include #include #include @@ -50,6 +53,16 @@ namespace sqlpp text_operand(_value_t t) : _t(std::move(t)) { } +#if __cplusplus >= 201703L + // allow construction from an std::string_view + text_operand(std::string_view t) : _t(t) + { + } + // additional const char* overload, required to disambiguate + text_operand(const char* t) : _t(t) + { + } +#endif text_operand(const text_operand&) = default; text_operand(text_operand&&) = default; diff --git a/include/sqlpp11/data_types/text/wrap_operand.h b/include/sqlpp11/data_types/text/wrap_operand.h index c2318e43..7a8f8a9f 100644 --- a/include/sqlpp11/data_types/text/wrap_operand.h +++ b/include/sqlpp11/data_types/text/wrap_operand.h @@ -28,6 +28,9 @@ #define SQLPP11_DATA_TYPES_TEXT_WRAP_OPERAND_H #include +#if __cplusplus >= 201703L +#include +#endif #include #include @@ -35,10 +38,16 @@ namespace sqlpp { struct text_operand; +#if __cplusplus >= 201703L + using checked_type = std::string_view; +#else + using checked_type = std::string; +#endif + template struct wrap_operand< T, - typename std::enable_if::value and not is_result_field_t::value>::type> + typename std::enable_if::value and not is_result_field_t::value>::type> { using type = text_operand; }; From 460557c6e0d6ea8ed996e38c72db3b0492ee3098 Mon Sep 17 00:00:00 2001 From: Daniel Evers Date: Mon, 28 Jan 2019 10:10:08 +0100 Subject: [PATCH 14/25] Added string_view tests and C++17 tests for travis --- .travis.yml | 4 +++- test_constraints/CMakeLists.txt | 6 ++++++ test_serializer/CMakeLists.txt | 7 +++++++ test_serializer/Insert.cpp | 6 ++++++ test_serializer/Where.cpp | 5 +++++ test_static_asserts/CMakeLists.txt | 6 ++++++ test_types/CMakeLists.txt | 6 ++++++ tests/CMakeLists.txt | 6 ++++++ 8 files changed, 45 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f94d0e1b..e07bb015 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ compiler: env: - CONFIG=Release + - CONFIG=Release TESTS_CXX_STD=17 #- CONFIG=Debug notifications: @@ -40,7 +41,8 @@ before_script: - cmake .. -DCMAKE_BUILD_TYPE=$CONFIG -DCMAKE_PREFIX_PATH=$PWD/../date script: - - cmake --build . --config $CONFIG + - [[ -n "$TESTS_CXX_STD" ]] && ARGS="-DSQLPP11_TESTS_CXX_STD=$TESTS_CXX_STD" + - cmake --build . --config $CONFIG $ARGS - ctest --output-on-failure after_script: diff --git a/test_constraints/CMakeLists.txt b/test_constraints/CMakeLists.txt index 1bfda1ed..e88f1a02 100644 --- a/test_constraints/CMakeLists.txt +++ b/test_constraints/CMakeLists.txt @@ -31,6 +31,12 @@ function(test_constraint name pattern) COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${target} ) set_property(TEST ${test} PROPERTY PASS_REGULAR_EXPRESSION ${pattern}) + # conditionally bump to a higher C++ standard to test compatibility + if (SQLPP11_TESTS_CXX_STD) + set_property(TARGET ${target} PROPERTY CXX_STANDARD ${SQLPP11_TESTS_CXX_STD}) + set_property(TARGET ${target} PROPERTY CXX_STANDARD_REQUIRED yes) + set_property(TARGET ${target} PROPERTY CXX_EXTENSIONS no) + endif() endfunction() # Compiling these is required to fail (testing some static_assert) diff --git a/test_serializer/CMakeLists.txt b/test_serializer/CMakeLists.txt index 042908e0..2e20950c 100644 --- a/test_serializer/CMakeLists.txt +++ b/test_serializer/CMakeLists.txt @@ -38,6 +38,13 @@ create_test_sourcelist(test_serializer_sources test_serializer_main.cpp ${test_s add_executable(sqlpp11_test_serializer ${test_serializer_sources}) target_link_libraries(sqlpp11_test_serializer PRIVATE sqlpp11 sqlpp11_testing) +# conditionally bump to a higher C++ standard to test compatibility +if (SQLPP11_TESTS_CXX_STD) + set_property(TARGET sqlpp11_test_serializer PROPERTY CXX_STANDARD ${SQLPP11_TESTS_CXX_STD}) + set_property(TARGET sqlpp11_test_serializer PROPERTY CXX_STANDARD_REQUIRED yes) + set_property(TARGET sqlpp11_test_serializer PROPERTY CXX_EXTENSIONS no) +endif() + foreach(test_serializer IN LISTS test_serializer_names) add_test(NAME sqlpp11.test_serializer.${test_serializer} COMMAND sqlpp11_test_serializer ${test_serializer} diff --git a/test_serializer/Insert.cpp b/test_serializer/Insert.cpp index e145cf7d..5cacf6eb 100644 --- a/test_serializer/Insert.cpp +++ b/test_serializer/Insert.cpp @@ -45,6 +45,12 @@ int Insert(int, char* []) compare(__LINE__, insert_into(bar).default_values(), "INSERT INTO tab_bar DEFAULT VALUES"); compare(__LINE__, insert_into(bar).set(bar.beta = "cheesecake", bar.gamma = true), "INSERT INTO tab_bar (beta,gamma) VALUES('cheesecake'," + getTrue() + ")"); +#if __cplusplus >= 201703L + // string_view argument + std::string_view cheeseCake = "cheesecake"; + compare(__LINE__, insert_into(bar).set(bar.beta = cheeseCake, bar.gamma = true), + "INSERT INTO tab_bar (beta,gamma) VALUES('cheesecake'," + getTrue() + ")"); +#endif return 0; } diff --git a/test_serializer/Where.cpp b/test_serializer/Where.cpp index a4e80112..ff369a99 100644 --- a/test_serializer/Where.cpp +++ b/test_serializer/Where.cpp @@ -62,6 +62,11 @@ int Where(int, char* []) compare(__LINE__, where(bar.gamma), " WHERE tab_bar.gamma"); compare(__LINE__, where(bar.gamma == false), " WHERE (tab_bar.gamma=" + getFalse() + ")"); compare(__LINE__, where(bar.beta == "SQL"), " WHERE (tab_bar.beta='SQL')"); +#if __cplusplus >= 201703L + // string_view argument + std::string_view sqlString = "SQL"; + compare(__LINE__, where(bar.beta == sqlString), " WHERE (tab_bar.beta='SQL')"); +#endif return 0; } diff --git a/test_static_asserts/CMakeLists.txt b/test_static_asserts/CMakeLists.txt index f9b76f35..9ecec43f 100644 --- a/test_static_asserts/CMakeLists.txt +++ b/test_static_asserts/CMakeLists.txt @@ -26,6 +26,12 @@ function(test_compile name) set(target sqlpp11_assert_${name}) add_executable(${target} ${name}.cpp) target_link_libraries(${target} PRIVATE sqlpp11 sqlpp11_testing) + # conditionally bump to a higher C++ standard to test compatibility + if (SQLPP11_TESTS_CXX_STD) + set_property(TARGET sqlpp11_assert_${name} PROPERTY CXX_STANDARD ${SQLPP11_TESTS_CXX_STD}) + set_property(TARGET sqlpp11_assert_${name} PROPERTY CXX_STANDARD_REQUIRED yes) + set_property(TARGET sqlpp11_assert_${name} PROPERTY CXX_EXTENSIONS no) + endif() endfunction() test_compile(aggregates) diff --git a/test_types/CMakeLists.txt b/test_types/CMakeLists.txt index cb2b8a8b..1d310542 100644 --- a/test_types/CMakeLists.txt +++ b/test_types/CMakeLists.txt @@ -26,6 +26,12 @@ function(test_compile name) set(target sqlpp11_${name}) add_executable(${target} ${name}.cpp) target_link_libraries(${target} PRIVATE sqlpp11 sqlpp11_testing) + # conditionally bump to a higher C++ standard to test compatibility + if (SQLPP11_TESTS_CXX_STD) + set_property(TARGET sqlpp11_${name} PROPERTY CXX_STANDARD ${SQLPP11_TESTS_CXX_STD}) + set_property(TARGET sqlpp11_${name} PROPERTY CXX_STANDARD_REQUIRED yes) + set_property(TARGET sqlpp11_${name} PROPERTY CXX_EXTENSIONS no) + endif() endfunction() test_compile(result_row) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 08bb2e9e..ed5d8a02 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -57,6 +57,12 @@ endif() create_test_sourcelist(test_sources test_main.cpp ${test_names}) add_executable(sqlpp11_tests ${test_sources}) target_link_libraries(sqlpp11_tests PRIVATE sqlpp11 sqlpp11_testing) +# conditionally bump to a higher C++ standard to test compatibility +if (SQLPP11_TESTS_CXX_STD) + set_property(TARGET sqlpp11_tests PROPERTY CXX_STANDARD ${SQLPP11_TESTS_CXX_STD}) + set_property(TARGET sqlpp11_tests PROPERTY CXX_STANDARD_REQUIRED yes) + set_property(TARGET sqlpp11_tests PROPERTY CXX_EXTENSIONS no) +endif() foreach(test IN LISTS test_names) add_test(NAME sqlpp11.tests.${test} From 076c9d6474263e4207e894490b74e54094eaa95c Mon Sep 17 00:00:00 2001 From: Daniel Evers Date: Mon, 28 Jan 2019 10:20:34 +0100 Subject: [PATCH 15/25] travis syntax problems... --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e07bb015..ef70bfd2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,9 @@ before_script: - cmake .. -DCMAKE_BUILD_TYPE=$CONFIG -DCMAKE_PREFIX_PATH=$PWD/../date script: - - [[ -n "$TESTS_CXX_STD" ]] && ARGS="-DSQLPP11_TESTS_CXX_STD=$TESTS_CXX_STD" + - if [[ -n "$TESTS_CXX_STD" ]]; then + ARGS="-DSQLPP11_TESTS_CXX_STD=$TESTS_CXX_STD" + fi - cmake --build . --config $CONFIG $ARGS - ctest --output-on-failure From a9f54984522f5e610a582d9cf1c5497665e56c50 Mon Sep 17 00:00:00 2001 From: Daniel Evers Date: Mon, 28 Jan 2019 10:50:58 +0100 Subject: [PATCH 16/25] suspicious build error on travis --- .travis.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index ef70bfd2..f731e33f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,10 +41,8 @@ before_script: - cmake .. -DCMAKE_BUILD_TYPE=$CONFIG -DCMAKE_PREFIX_PATH=$PWD/../date script: - - if [[ -n "$TESTS_CXX_STD" ]]; then - ARGS="-DSQLPP11_TESTS_CXX_STD=$TESTS_CXX_STD" - fi - - cmake --build . --config $CONFIG $ARGS + - if [[ -n "${TESTS_CXX_STD:-}" ]]; then ARGS="-DSQLPP11_TESTS_CXX_STD=$TESTS_CXX_STD"; fi + - cmake --build . --config $CONFIG ${ARGS:-} - ctest --output-on-failure after_script: From 949089d9f364c6535bff9f2732dbdfe11c627939 Mon Sep 17 00:00:00 2001 From: Daniel Evers Date: Mon, 28 Jan 2019 11:00:08 +0100 Subject: [PATCH 17/25] avoid expanding empty variables --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f731e33f..bf52446b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,8 +41,9 @@ before_script: - cmake .. -DCMAKE_BUILD_TYPE=$CONFIG -DCMAKE_PREFIX_PATH=$PWD/../date script: - - if [[ -n "${TESTS_CXX_STD:-}" ]]; then ARGS="-DSQLPP11_TESTS_CXX_STD=$TESTS_CXX_STD"; fi - - cmake --build . --config $CONFIG ${ARGS:-} + - ARGS="--config $CONFIG" + - if [[ -n "${TESTS_CXX_STD:-}" ]]; then ARGS="$ARGS -DSQLPP11_TESTS_CXX_STD=$TESTS_CXX_STD"; fi + - cmake --build . $ARGS - ctest --output-on-failure after_script: From 42de1557b2386c4082cb76fa81531728b41046c7 Mon Sep 17 00:00:00 2001 From: Daniel Evers Date: Mon, 28 Jan 2019 11:12:38 +0100 Subject: [PATCH 18/25] need to override CMAKE vars before building --- .travis.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index bf52446b..d7d80056 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,12 +38,11 @@ before_script: sudo apt-get install python-pyparsing; fi - if [[ "$CXX" = "g++" && "$CONFIG" = "Debug" && "$TRAVIS_OS_NAME" = "linux" ]]; then export CXXFLAGS="--coverage"; fi - - cmake .. -DCMAKE_BUILD_TYPE=$CONFIG -DCMAKE_PREFIX_PATH=$PWD/../date + - if [[ -n "${TESTS_CXX_STD:-}" ]]; then ADD_OPTS="-DSQLPP11_TESTS_CXX_STD=$TESTS_CXX_STD"; fi + - cmake .. -DCMAKE_BUILD_TYPE=$CONFIG -DCMAKE_PREFIX_PATH=$PWD/../date $ADD_OPTS script: - - ARGS="--config $CONFIG" - - if [[ -n "${TESTS_CXX_STD:-}" ]]; then ARGS="$ARGS -DSQLPP11_TESTS_CXX_STD=$TESTS_CXX_STD"; fi - - cmake --build . $ARGS + - cmake --build . --config $CONFIG - ctest --output-on-failure after_script: From 93670717643595bc794362135e96e7bafe1315bd Mon Sep 17 00:00:00 2001 From: Daniel Evers Date: Mon, 28 Jan 2019 11:24:47 +0100 Subject: [PATCH 19/25] enable C++ 17 tests only on OS X (the clang and gcc versions on Linux are too old) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d7d80056..9ec66b3f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ before_script: sudo apt-get install python-pyparsing; fi - if [[ "$CXX" = "g++" && "$CONFIG" = "Debug" && "$TRAVIS_OS_NAME" = "linux" ]]; then export CXXFLAGS="--coverage"; fi - - if [[ -n "${TESTS_CXX_STD:-}" ]]; then ADD_OPTS="-DSQLPP11_TESTS_CXX_STD=$TESTS_CXX_STD"; fi + - if [[ -n "${TESTS_CXX_STD:-}" && "$TRAVIS_OS_NAME" = "osx" ]]; then ADD_OPTS="-DSQLPP11_TESTS_CXX_STD=$TESTS_CXX_STD"; fi - cmake .. -DCMAKE_BUILD_TYPE=$CONFIG -DCMAKE_PREFIX_PATH=$PWD/../date $ADD_OPTS script: From d1b8bde8f1b335ff06fb7806e2ed079265aad360 Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 27 Feb 2019 13:53:28 +0100 Subject: [PATCH 20/25] Cleanup bogus return statements --- include/sqlpp11/group_by.h | 2 +- include/sqlpp11/having.h | 2 +- include/sqlpp11/order_by.h | 2 +- include/sqlpp11/select_column_list.h | 2 +- include/sqlpp11/select_flag_list.h | 2 +- include/sqlpp11/update_list.h | 2 +- include/sqlpp11/using.h | 2 +- include/sqlpp11/where.h | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/sqlpp11/group_by.h b/include/sqlpp11/group_by.h index 3066e917..91985459 100644 --- a/include/sqlpp11/group_by.h +++ b/include/sqlpp11/group_by.h @@ -102,7 +102,7 @@ namespace sqlpp template void _add_impl(Expression expression, const std::true_type& /*unused*/) { - return _data._dynamic_expressions.emplace_back(expression); + _data._dynamic_expressions.emplace_back(expression); } template diff --git a/include/sqlpp11/having.h b/include/sqlpp11/having.h index ee451fb5..ff377052 100644 --- a/include/sqlpp11/having.h +++ b/include/sqlpp11/having.h @@ -103,7 +103,7 @@ namespace sqlpp template void _add_impl(Expr expression, const std::true_type& /*unused*/) { - return _data._dynamic_expressions.emplace_back(expression); + _data._dynamic_expressions.emplace_back(expression); } template diff --git a/include/sqlpp11/order_by.h b/include/sqlpp11/order_by.h index 1ca1758d..d1ef5da4 100644 --- a/include/sqlpp11/order_by.h +++ b/include/sqlpp11/order_by.h @@ -100,7 +100,7 @@ namespace sqlpp template void _add_impl(Expression expression, const std::true_type& /*unused*/) { - return _data._dynamic_expressions.emplace_back(expression); + _data._dynamic_expressions.emplace_back(expression); } template diff --git a/include/sqlpp11/select_column_list.h b/include/sqlpp11/select_column_list.h index c10a3858..05c28698 100644 --- a/include/sqlpp11/select_column_list.h +++ b/include/sqlpp11/select_column_list.h @@ -147,7 +147,7 @@ namespace sqlpp template void _add_impl(NamedExpression namedExpression, const std::true_type& /*unused*/) { - return _data._dynamic_columns.emplace_back(auto_alias_t{namedExpression}); + _data._dynamic_columns.emplace_back(auto_alias_t{namedExpression}); } template diff --git a/include/sqlpp11/select_flag_list.h b/include/sqlpp11/select_flag_list.h index 92ec5ba1..0420b200 100644 --- a/include/sqlpp11/select_flag_list.h +++ b/include/sqlpp11/select_flag_list.h @@ -96,7 +96,7 @@ namespace sqlpp template void _add_impl(Flag flag, const std::true_type& /*unused*/) { - return _data._dynamic_flags.emplace_back(flag); + _data._dynamic_flags.emplace_back(flag); } template diff --git a/include/sqlpp11/update_list.h b/include/sqlpp11/update_list.h index b6b5d3db..746cdd6a 100644 --- a/include/sqlpp11/update_list.h +++ b/include/sqlpp11/update_list.h @@ -100,7 +100,7 @@ namespace sqlpp template void _add_impl(Assignment assignment, const std::true_type& /*unused*/) { - return _data._dynamic_assignments.emplace_back(assignment); + _data._dynamic_assignments.emplace_back(assignment); } template diff --git a/include/sqlpp11/using.h b/include/sqlpp11/using.h index 8d368c5c..409e2bae 100644 --- a/include/sqlpp11/using.h +++ b/include/sqlpp11/using.h @@ -92,7 +92,7 @@ namespace sqlpp template void _add_impl(Table table, const std::true_type& /*unused*/) { - return _data._dynamic_tables.emplace_back(table); + _data._dynamic_tables.emplace_back(table); } template diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index 9acf0a4c..d79d390e 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -105,7 +105,7 @@ namespace sqlpp template void _add_impl(Expr expression, const std::true_type& /*unused*/) { - return _data._dynamic_expressions.emplace_back(expression); + _data._dynamic_expressions.emplace_back(expression); } template From 80e25a5e52747f49e096e0cdbe781123a9bc76a1 Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 3 Mar 2019 09:11:33 +0100 Subject: [PATCH 21/25] Add `AUTOINCREMENT` support in ddl2cpp for sqlite3 --- scripts/ddl2cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/ddl2cpp b/scripts/ddl2cpp index 133aea64..42344f72 100755 --- a/scripts/ddl2cpp +++ b/scripts/ddl2cpp @@ -137,7 +137,7 @@ optionalArgs = { '-fail-on-parse': "abort instead of silent genereation of unusable headers", # failOnParse = True '-warn-on-parse': "warn about unusable headers, but continue", # warnOnParse = True '-auto-id': "Assume column 'id' to have an automatic value as if AUTO_INCREMENT was specified (e.g. implicit for SQLite ROWID)", # autoId = True - '-identity-naming': "Use table and column names from the ddl (defaults to UpperCamelCase for tables and lowerCamelCase for columns", # identityNaming = True + '-identity-naming': "Use table and column names from the ddl (defaults to UpperCamelCase for tables and lowerCamelCase for columns)", # identityNaming = True '-split-tables': "Make a header for each table name, using target as a directory", # splitTables = True '-help': "show this help" } @@ -215,6 +215,7 @@ ddlNotNull = Group(ddlWord("NOT") + ddlWord("NULL")).setResultsName("notNull") ddlDefaultValue = ddlWord("DEFAULT").setResultsName("hasDefaultValue") ddlAutoValue = Or([ ddlWord("AUTO_INCREMENT"), + ddlWord("AUTOINCREMENT"), ddlWord("SMALLSERIAL"), ddlWord("SERIAL"), ddlWord("BIGSERIAL"), From 6f39293a69d022c6123d0047e4fbe792f73014b4 Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 19 Mar 2019 06:38:01 +0100 Subject: [PATCH 22/25] Maybe make MSVC happy again... Thanks, @juandent for the change suggestion --- include/sqlpp11/char_sequence.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/sqlpp11/char_sequence.h b/include/sqlpp11/char_sequence.h index 57595258..a5c105c8 100644 --- a/include/sqlpp11/char_sequence.h +++ b/include/sqlpp11/char_sequence.h @@ -54,18 +54,19 @@ namespace sqlpp } }; - template + template struct make_char_sequence_impl; - template + template struct make_char_sequence_impl> { using type = char_sequence; }; - template + template using make_char_sequence = typename make_char_sequence_impl>::type; + } // namespace sqlpp #endif From b27406a87e3dd464c8bff114704132f530a3c5ad Mon Sep 17 00:00:00 2001 From: rbock Date: Fri, 22 Mar 2019 05:40:03 +0100 Subject: [PATCH 23/25] Make implicit array to pointer decay explicit --- include/sqlpp11/char_sequence.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sqlpp11/char_sequence.h b/include/sqlpp11/char_sequence.h index a5c105c8..4d6144c1 100644 --- a/include/sqlpp11/char_sequence.h +++ b/include/sqlpp11/char_sequence.h @@ -54,16 +54,16 @@ namespace sqlpp } }; - template + template struct make_char_sequence_impl; - template + template struct make_char_sequence_impl> { using type = char_sequence; }; - template + template using make_char_sequence = typename make_char_sequence_impl>::type; From c729387ab66b19acdff02f047660bdda8f75b343 Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 11 Apr 2019 11:30:25 +0200 Subject: [PATCH 24/25] Allow INSERT INTO from SELECT --- include/sqlpp11/insert_value_list.h | 26 +++++++++++++++----------- test_serializer/CustomQuery.cpp | 20 ++++++++++++++++---- tests/Insert.cpp | 6 ++++-- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/include/sqlpp11/insert_value_list.h b/include/sqlpp11/insert_value_list.h index 10fe19e6..56c36104 100644 --- a/include/sqlpp11/insert_value_list.h +++ b/include/sqlpp11/insert_value_list.h @@ -627,17 +627,17 @@ namespace sqlpp context << " ("; interpret_tuple(t._columns, ",", context); context << ")"; - context << " VALUES "; bool first = true; for (const auto& row : t._insert_values) { - if (not first) + if (first) { - context << ','; + context << " VALUES "; + first = false; } else { - first = false; + context << ','; } context << '('; interpret_tuple(row, ",", context); @@ -669,14 +669,18 @@ namespace sqlpp context << ','; } interpret_list(t._dynamic_columns, ',', context); - context << ") VALUES("; - interpret_tuple(t._values, ",", context); - if (sizeof...(Assignments) and not t._dynamic_values.empty()) - { - context << ','; - } - interpret_list(t._dynamic_values, ',', context); context << ")"; + if (sizeof...(Assignments) or not t._dynamic_values.empty()) + { + context << " VALUES("; + interpret_tuple(t._values, ",", context); + if (sizeof...(Assignments) and not t._dynamic_values.empty()) + { + context << ','; + } + interpret_list(t._dynamic_values, ',', context); + context << ")"; + } } return context; } diff --git a/test_serializer/CustomQuery.cpp b/test_serializer/CustomQuery.cpp index 4c00aec5..f86a859d 100644 --- a/test_serializer/CustomQuery.cpp +++ b/test_serializer/CustomQuery.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2016, Roland Bock + * Copyright (c) 2016-2019, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -31,15 +31,16 @@ SQLPP_ALIAS_PROVIDER(pragma) -int CustomQuery(int, char* []) +int CustomQuery(int, char*[]) { const auto foo = test::TabFoo{}; const auto bar = test::TabBar{}; auto db = MockDb{}; // Unconditionally - compare(__LINE__, custom_query(sqlpp::select(), select_flags(sqlpp::distinct), select_columns(foo.omega), from(foo), - sqlpp::unconditionally()), + compare(__LINE__, + custom_query(sqlpp::select(), select_flags(sqlpp::distinct), select_columns(foo.omega), from(foo), + sqlpp::unconditionally()), "SELECT DISTINCT tab_foo.omega FROM tab_foo "); // A full select statement made individual clauses @@ -68,5 +69,16 @@ int CustomQuery(int, char* []) custom_query(sqlpp::verbatim("PRAGMA user_version")).with_result_type_of(select(sqlpp::value(1).as(pragma))), " PRAGMA user_version"); + // An insert from select for postgresql + const auto x = 17; + compare(__LINE__, + custom_query(insert_into(foo).columns(foo.omega), + select(sqlpp::value(x).as(foo.omega)) + .from(foo) + .where(not exists(select(foo.omega).from(foo).where(foo.omega == x)))), + "INSERT INTO tab_foo (omega) " + "SELECT 17 AS omega FROM tab_foo " + "WHERE (NOT EXISTS(SELECT tab_foo.omega FROM tab_foo WHERE (tab_foo.omega=17)))"); + return 0; } diff --git a/tests/Insert.cpp b/tests/Insert.cpp index a364fdce..34e3a48c 100644 --- a/tests/Insert.cpp +++ b/tests/Insert.cpp @@ -66,9 +66,11 @@ int Insert(int, char*[]) multi_insert.values.add(t.gamma = true, t.beta = "cheesecake", t.delta = 1); multi_insert.values.add(t.gamma = sqlpp::default_value, t.beta = sqlpp::default_value, t.delta = sqlpp::default_value); - multi_insert.values.add(t.gamma = sqlpp::value_or_null(true), - t.beta = sqlpp::value_or_null("pie"), + multi_insert.values.add(t.gamma = sqlpp::value_or_null(true), t.beta = sqlpp::value_or_null("pie"), t.delta = sqlpp::value_or_null(sqlpp::null)); + printer.reset(); + std::cerr << serialize(multi_insert, printer).str() << std::endl; + auto i = dynamic_insert_into(db, t).dynamic_set(); i.insert_list.add(t.beta = "kirschauflauf"); printer.reset(); From 60267ab952e3b20e0d4c58736b027baf2c0ff382 Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 18 Apr 2019 08:54:17 +0200 Subject: [PATCH 25/25] Added an example for reading time point values --- tests/DateTime.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/DateTime.cpp b/tests/DateTime.cpp index 2e3a6f0c..56dc78ed 100644 --- a/tests/DateTime.cpp +++ b/tests/DateTime.cpp @@ -37,7 +37,7 @@ using ::std::chrono::floor; using ::date::floor; #endif -int DateTime(int, char* []) +int DateTime(int, char*[]) { MockDb db = {}; MockDb::_serializer_context_t printer = {}; @@ -51,6 +51,8 @@ int DateTime(int, char* []) { std::cout << row.colDayPoint; std::cout << row.colTimePoint; + const auto tp = std::chrono::system_clock::time_point{row.colTimePoint.value()}; + std::cout << std::chrono::system_clock::to_time_t(tp); } printer.reset(); std::cerr << serialize(::sqlpp::value(std::chrono::system_clock::now()), printer).str() << std::endl;