mirror of
https://github.com/rbock/sqlpp11.git
synced 2024-11-16 04:47:18 +08:00
Merge tag '0.36' into develop
Several breaking changes: * `from(a,b)` not allowed anymore, please use explicit joins * `where(true)` not allowed anymore, please use `.unconditionally()` or sqlpp::value(true) * `some_sql_expression and true` not allowed anymore, please use `tab.col == sqlpp::value(true)` if you really want to express this. * `having(expression)` requires `expression` to be made of aggregates, e.g. columns named in `group_by()` or aggregate functions like `count()` or constant values. * `where()` and `having()` accept only one parameter Several more clauses are now available as free functions. Lots of additional tests.
This commit is contained in:
commit
e629086e72
109
ChangeLog.md
Normal file
109
ChangeLog.md
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
Important changes in sqlpp11
|
||||||
|
============================
|
||||||
|
|
||||||
|
Breaking changes in 0.36:
|
||||||
|
-------------------------
|
||||||
|
__Abstract__:
|
||||||
|
|
||||||
|
One of the main motivations of sqlpp11 is to prevent SQL programming mistakes at compile time. The following changes prevent reported mishaps.
|
||||||
|
* `from(a,b)` not allowed anymore, please use explicit joins
|
||||||
|
* `where(true)` not allowed anymore, please use `.unconditionally()` or sqlpp::value(true)
|
||||||
|
* `some_sql_expression and true` not allowed anymore, please use `tab.col == sqlpp::value(true)` if you really want to express this.
|
||||||
|
* `having(expression)` requires `expression` to be made of aggregates, e.g. columns named in `group_by()` or aggregate functions like `count()` or constant values.
|
||||||
|
* `where()` and `having` accept only one parameter
|
||||||
|
|
||||||
|
__Explicit joins required__:
|
||||||
|
|
||||||
|
Up until sqlpp11-0.35 you could write something like
|
||||||
|
|
||||||
|
```
|
||||||
|
auto result = db(select(all_of(a), all_of(b))
|
||||||
|
.from(a,b)
|
||||||
|
.where(true));
|
||||||
|
```
|
||||||
|
|
||||||
|
Using this syntax in `from()`, it was expected to have the join condition implicitly in the `where()` call.
|
||||||
|
But there is no reliable way to tell whether or not that condition is there. Or, if there definitely is none, whether
|
||||||
|
it was omitted on purpose or by accident.
|
||||||
|
In one case, an accidentally omitted join condition in the `where()` brought a production system to a screeching halt.
|
||||||
|
|
||||||
|
In order to prevent this in the future, sqlpp11 now requires you to join table explicitly, including an explicit join condition, e.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
auto result = db(select(all_of(a), all_of(b))
|
||||||
|
.from(a.join(b).on(a.b == b.id))
|
||||||
|
.where(true));
|
||||||
|
```
|
||||||
|
|
||||||
|
Most joins, (`join`/`inner_join`, `left_outer_join`, `right_outer_join` and `outer_join`) require a join condition to given via `on()`.
|
||||||
|
The join condition has to be some sqlpp11 boolean expression.
|
||||||
|
|
||||||
|
In those rare cases, when you really need a cross join, you can also use `cross_join()` which has no join condition, of course.
|
||||||
|
|
||||||
|
```
|
||||||
|
auto result = db(select(all_of(a), all_of(b))
|
||||||
|
.from(a.cross_join(b))
|
||||||
|
.where(true));
|
||||||
|
```
|
||||||
|
|
||||||
|
__Use `.unconditionally()`__
|
||||||
|
|
||||||
|
If you want to select/update/remove all rows, earlier versions of sqlpp11 required the use of `where(true)`. Since version 0.36, use `unconditionally()`, for instance:
|
||||||
|
```
|
||||||
|
auto result = db(select(all_of(t)).from(t).unconditionally());
|
||||||
|
```
|
||||||
|
|
||||||
|
__Use `sqlpp::value()` to wrap bool values in boolean expressions__
|
||||||
|
|
||||||
|
Lets say you had
|
||||||
|
|
||||||
|
```
|
||||||
|
struct X
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
int b;
|
||||||
|
};
|
||||||
|
auto x = X{};
|
||||||
|
```
|
||||||
|
|
||||||
|
Then earlier versions of sqlpp11 would compile the following expression:
|
||||||
|
|
||||||
|
```
|
||||||
|
select(all_of(t)).from(t).where(x.a == x.a or t.b == t.b);
|
||||||
|
```
|
||||||
|
|
||||||
|
What you probably meant was:
|
||||||
|
|
||||||
|
```
|
||||||
|
select(all_of(t)).from(t).where(t.a == x.a and t.b == x.b);
|
||||||
|
```
|
||||||
|
|
||||||
|
In order to prevent this kind of mistake, boolean operators in sql expressions require sqlpp boolean expressions as operators.
|
||||||
|
The library also requires the types of the left/right hand side operands of a comparison to be different, so that `t.a < t.a` does not compile any more.
|
||||||
|
|
||||||
|
In the rare case you really have a bool value that you want to use a boolean sql expression, you have to wrap it in sqlpp::value(x), e.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
select(all_of(t)).from(t).where(sqlpp::value(x.a == 17) and t.b == x.b);
|
||||||
|
```
|
||||||
|
|
||||||
|
__`having()` requires aggregate expressions__
|
||||||
|
|
||||||
|
In older versions, the following code was allowed:
|
||||||
|
|
||||||
|
```
|
||||||
|
select(all_of(t)).from(t).where(t.a > 7).having(t.b != "");
|
||||||
|
```
|
||||||
|
|
||||||
|
As of sqlpp11-0.36, the having argument must be made of aggregate columns or functions, e.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
select(all_of(t)).from(t).unconditionally().group_by(t.b).having(t.b != "", avg(t.c) < 42);
|
||||||
|
```
|
||||||
|
|
||||||
|
__`where()` and `having` accept only one expression__
|
||||||
|
|
||||||
|
In older versions, `where()` and `having()` would accept more than one argument and combine those arguments with `and`.
|
||||||
|
I am not sure this was ever used. So it just made life harder for the compiler.
|
||||||
|
|
||||||
|
As of version 0.36, `where()` and `having()` accept only one parameter.
|
15
README.md
15
README.md
@ -145,11 +145,22 @@ Basic usage:
|
|||||||
__Linux install:__
|
__Linux install:__
|
||||||
git clone date library, needed connectors, cmake and make install them.
|
git clone date library, needed connectors, cmake and make install them.
|
||||||
|
|
||||||
create DDL files (like mysql: 'show create table MyDatabase.MyTable', but remove backticks), create headers for them with provided python script:
|
|
||||||
|
__Create DDL files__:
|
||||||
|
```
|
||||||
|
mysql: 'show create table MyDatabase.MyTable' #or
|
||||||
|
mysqldump --no-data MyDatabase > MyDatabase.sql
|
||||||
|
|
||||||
|
```
|
||||||
|
Create headers for them with provided python script:
|
||||||
```
|
```
|
||||||
%sqlpp11_dir%/scripts/ddl2cpp ~/temp/MyTable.ddl ~/temp/MyTable %DatabaseNamespaceForExample%
|
%sqlpp11_dir%/scripts/ddl2cpp ~/temp/MyTable.ddl ~/temp/MyTable %DatabaseNamespaceForExample%
|
||||||
```
|
```
|
||||||
include generated header (MyTable.h), that's all
|
(In case you're getting notes about unsupported column type take a look at the other datatypes in sqlpp11/data_types. They are not hard to implement.)
|
||||||
|
|
||||||
|
Include generated header (MyTable.h), that's all
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
License:
|
License:
|
||||||
|
@ -128,6 +128,8 @@ types = {
|
|||||||
'date' : 'day_point',
|
'date' : 'day_point',
|
||||||
'datetime' : 'time_point',
|
'datetime' : 'time_point',
|
||||||
'timestamp' : 'time_point',
|
'timestamp' : 'time_point',
|
||||||
|
'enum' : 'text', # MYSQL
|
||||||
|
'set' : 'text', # MYSQL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -145,7 +147,7 @@ print('#include <' + INCLUDE + '/char_sequence.h>', file=header)
|
|||||||
print('', file=header)
|
print('', file=header)
|
||||||
print('namespace ' + namespace, file=header)
|
print('namespace ' + namespace, file=header)
|
||||||
print('{', file=header)
|
print('{', file=header)
|
||||||
|
DataTypeError = False;
|
||||||
for create in tableCreations:
|
for create in tableCreations:
|
||||||
sqlTableName = create.tableName
|
sqlTableName = create.tableName
|
||||||
tableClass = toClassName(sqlTableName)
|
tableClass = toClassName(sqlTableName)
|
||||||
@ -181,7 +183,11 @@ for create in tableCreations:
|
|||||||
print(' const T& operator()() const { return ' + columnMember + '; }', file=header)
|
print(' const T& operator()() const { return ' + columnMember + '; }', file=header)
|
||||||
print(' };', file=header)
|
print(' };', file=header)
|
||||||
print(' };', file=header)
|
print(' };', file=header)
|
||||||
traitslist = [NAMESPACE + '::' + types[sqlColumnType]];
|
try:
|
||||||
|
traitslist = [NAMESPACE + '::' + types[sqlColumnType]];
|
||||||
|
except KeyError as e:
|
||||||
|
print ('Error: datatype "' + sqlColumnType + '"" is not supported.')
|
||||||
|
DataTypeError = True
|
||||||
requireInsert = True
|
requireInsert = True
|
||||||
if column.hasAutoValue:
|
if column.hasAutoValue:
|
||||||
traitslist.append(NAMESPACE + '::tag::must_not_insert');
|
traitslist.append(NAMESPACE + '::tag::must_not_insert');
|
||||||
@ -217,4 +223,10 @@ for create in tableCreations:
|
|||||||
|
|
||||||
print('}', file=header)
|
print('}', file=header)
|
||||||
print('#endif', 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
|
||||||
|
Loading…
Reference in New Issue
Block a user