@@ -1102,14 +1102,14 @@ public function testColumnWithOnUpdate() {
11021102 'name ' => '___tmp_table_created_at_on_update__ ' ,
11031103 'tbl_name ' => '_tmp_table ' ,
11041104 'rootpage ' => '0 ' ,
1105- 'sql ' => "CREATE TRIGGER \"___tmp_table_created_at_on_update__ \"\n\t\t\tAFTER UPDATE ON \"_tmp_table \"\n\t\t\tFOR EACH ROW \n\t\t\tBEGIN \n\t\t\t UPDATE \"_tmp_table \" SET \"created_at \" = CURRENT_TIMESTAMP WHERE id = NEW.id ; \n\t\t\tEND " ,
1105+ 'sql ' => "CREATE TRIGGER \"___tmp_table_created_at_on_update__ \"\n\t\t\tAFTER UPDATE ON \"_tmp_table \"\n\t\t\tFOR EACH ROW \n\t\t\tBEGIN \n\t\t\t UPDATE \"_tmp_table \" SET \"created_at \" = CURRENT_TIMESTAMP WHERE rowid = NEW.rowid ; \n\t\t\tEND " ,
11061106 ),
11071107 (object ) array (
11081108 'type ' => 'trigger ' ,
11091109 'name ' => '___tmp_table_updated_at_on_update__ ' ,
11101110 'tbl_name ' => '_tmp_table ' ,
11111111 'rootpage ' => '0 ' ,
1112- 'sql ' => "CREATE TRIGGER \"___tmp_table_updated_at_on_update__ \"\n\t\t\tAFTER UPDATE ON \"_tmp_table \"\n\t\t\tFOR EACH ROW \n\t\t\tBEGIN \n\t\t\t UPDATE \"_tmp_table \" SET \"updated_at \" = CURRENT_TIMESTAMP WHERE id = NEW.id ; \n\t\t\tEND " ,
1112+ 'sql ' => "CREATE TRIGGER \"___tmp_table_updated_at_on_update__ \"\n\t\t\tAFTER UPDATE ON \"_tmp_table \"\n\t\t\tFOR EACH ROW \n\t\t\tBEGIN \n\t\t\t UPDATE \"_tmp_table \" SET \"updated_at \" = CURRENT_TIMESTAMP WHERE rowid = NEW.rowid ; \n\t\t\tEND " ,
11131113 ),
11141114 ),
11151115 $ results
@@ -1176,6 +1176,150 @@ public function testColumnWithOnUpdate() {
11761176 $ this ->assertNull ( $ result [0 ]->updated_at );
11771177 }
11781178
1179+ public function testColumnWithOnUpdateAndNoIdField () {
1180+ // CREATE TABLE with ON UPDATE
1181+ $ this ->assertQuery (
1182+ 'CREATE TABLE _tmp_table (
1183+ name varchar(20) NOT NULL,
1184+ created_at timestamp NULL ON UPDATE CURRENT_TIMESTAMP
1185+ ); '
1186+ );
1187+
1188+ // on INSERT, no timestamps are expected
1189+ $ this ->assertQuery ( "INSERT INTO _tmp_table (name) VALUES ('aaa') " );
1190+ $ result = $ this ->assertQuery ( "SELECT * FROM _tmp_table WHERE name = 'aaa' " );
1191+ $ this ->assertNull ( $ result [0 ]->created_at );
1192+
1193+ // on UPDATE, we expect timestamps in form YYYY-MM-DD HH:MM:SS
1194+ $ this ->assertQuery ( "UPDATE _tmp_table SET name = 'bbb' WHERE name = 'aaa' " );
1195+ $ result = $ this ->assertQuery ( "SELECT * FROM _tmp_table WHERE name = 'bbb' " );
1196+ $ this ->assertRegExp ( '/\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/ ' , $ result [0 ]->created_at );
1197+ }
1198+
1199+ public function testColumnWithOnUpdateAndAutoincrementPrimaryKey () {
1200+ // CREATE TABLE with ON UPDATE, AUTO_INCREMENT, and PRIMARY KEY
1201+ $ this ->assertQuery (
1202+ 'CREATE TABLE _tmp_table (
1203+ id int(11) NOT NULL AUTO_INCREMENT,
1204+ created_at timestamp NULL ON UPDATE CURRENT_TIMESTAMP,
1205+ PRIMARY KEY (id)
1206+ ); '
1207+ );
1208+
1209+ // on INSERT, no timestamps are expected
1210+ $ this ->assertQuery ( 'INSERT INTO _tmp_table (id) VALUES (1) ' );
1211+ $ result = $ this ->assertQuery ( 'SELECT * FROM _tmp_table WHERE id = 1 ' );
1212+ $ this ->assertNull ( $ result [0 ]->created_at );
1213+
1214+ // on UPDATE, we expect timestamps in form YYYY-MM-DD HH:MM:SS
1215+ $ this ->assertQuery ( 'UPDATE _tmp_table SET id = 2 WHERE id = 1 ' );
1216+ $ result = $ this ->assertQuery ( 'SELECT * FROM _tmp_table WHERE id = 2 ' );
1217+ $ this ->assertRegExp ( '/\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/ ' , $ result [0 ]->created_at );
1218+ }
1219+
1220+ public function testChangeColumnWithOnUpdate () {
1221+ // CREATE TABLE with ON UPDATE
1222+ $ this ->assertQuery (
1223+ 'CREATE TABLE _tmp_table (
1224+ id int(11) NOT NULL,
1225+ created_at timestamp NULL
1226+ ); '
1227+ );
1228+ $ results = $ this ->assertQuery ( 'DESCRIBE _tmp_table; ' );
1229+ $ this ->assertEquals (
1230+ array (
1231+ (object ) array (
1232+ 'Field ' => 'id ' ,
1233+ 'Type ' => 'int(11) ' ,
1234+ 'Null ' => 'NO ' ,
1235+ 'Key ' => '' ,
1236+ 'Default ' => '0 ' ,
1237+ 'Extra ' => '' ,
1238+ ),
1239+ (object ) array (
1240+ 'Field ' => 'created_at ' ,
1241+ 'Type ' => 'timestamp ' ,
1242+ 'Null ' => 'YES ' ,
1243+ 'Key ' => '' ,
1244+ 'Default ' => null ,
1245+ 'Extra ' => '' ,
1246+ ),
1247+ ),
1248+ $ results
1249+ );
1250+
1251+ // no ON UPDATE is set
1252+ $ this ->assertQuery ( 'INSERT INTO _tmp_table (id) VALUES (1) ' );
1253+ $ this ->assertQuery ( 'UPDATE _tmp_table SET id = 1 WHERE id = 1 ' );
1254+ $ result = $ this ->assertQuery ( 'SELECT * FROM _tmp_table WHERE id = 1 ' );
1255+ $ this ->assertNull ( $ result [0 ]->created_at );
1256+
1257+ // CHANGE COLUMN to add ON UPDATE
1258+ $ this ->assertQuery (
1259+ 'ALTER TABLE _tmp_table CHANGE COLUMN created_at created_at timestamp NULL ON UPDATE CURRENT_TIMESTAMP '
1260+ );
1261+ $ results = $ this ->assertQuery ( 'DESCRIBE _tmp_table; ' );
1262+ $ this ->assertEquals (
1263+ array (
1264+ (object ) array (
1265+ 'Field ' => 'id ' ,
1266+ 'Type ' => 'int(11) ' ,
1267+ 'Null ' => 'NO ' ,
1268+ 'Key ' => '' ,
1269+ 'Default ' => '0 ' ,
1270+ 'Extra ' => '' ,
1271+ ),
1272+ (object ) array (
1273+ 'Field ' => 'created_at ' ,
1274+ 'Type ' => 'timestamp ' ,
1275+ 'Null ' => 'YES ' ,
1276+ 'Key ' => '' ,
1277+ 'Default ' => null ,
1278+ 'Extra ' => '' ,
1279+ ),
1280+ ),
1281+ $ results
1282+ );
1283+
1284+ // now, ON UPDATE SHOULD BE SET
1285+ $ this ->assertQuery ( 'UPDATE _tmp_table SET id = 1 WHERE id = 1 ' );
1286+ $ result = $ this ->assertQuery ( 'SELECT * FROM _tmp_table WHERE id = 1 ' );
1287+ $ this ->assertRegExp ( '/\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/ ' , $ result [0 ]->created_at );
1288+
1289+ // change column to remove ON UPDATE
1290+ $ this ->assertQuery (
1291+ 'ALTER TABLE _tmp_table CHANGE COLUMN created_at created_at timestamp NULL '
1292+ );
1293+ $ results = $ this ->assertQuery ( 'DESCRIBE _tmp_table; ' );
1294+ $ this ->assertEquals (
1295+ array (
1296+ (object ) array (
1297+ 'Field ' => 'id ' ,
1298+ 'Type ' => 'int(11) ' ,
1299+ 'Null ' => 'NO ' ,
1300+ 'Key ' => '' ,
1301+ 'Default ' => '0 ' ,
1302+ 'Extra ' => '' ,
1303+ ),
1304+ (object ) array (
1305+ 'Field ' => 'created_at ' ,
1306+ 'Type ' => 'timestamp ' ,
1307+ 'Null ' => 'YES ' ,
1308+ 'Key ' => '' ,
1309+ 'Default ' => null ,
1310+ 'Extra ' => '' ,
1311+ ),
1312+ ),
1313+ $ results
1314+ );
1315+
1316+ // now, no timestamp is expected
1317+ $ this ->assertQuery ( 'INSERT INTO _tmp_table (id) VALUES (2) ' );
1318+ $ this ->assertQuery ( 'UPDATE _tmp_table SET id = 2 WHERE id = 2 ' );
1319+ $ result = $ this ->assertQuery ( 'SELECT * FROM _tmp_table WHERE id = 2 ' );
1320+ $ this ->assertNull ( $ result [0 ]->created_at );
1321+ }
1322+
11791323 public function testAlterTableWithColumnFirstAndAfter () {
11801324 $ this ->assertQuery (
11811325 "CREATE TABLE _tmp_table (
@@ -3133,6 +3277,85 @@ public function testCurrentTimestamp() {
31333277 $ this ->assertQuery ( 'DELETE FROM _dates WHERE option_value = CURRENT_TIMESTAMP() ' );
31343278 }
31353279
3280+ public function testGroupByHaving () {
3281+ $ this ->assertQuery (
3282+ 'CREATE TABLE _tmp_table (
3283+ name varchar(20)
3284+ ); '
3285+ );
3286+
3287+ $ this ->assertQuery (
3288+ "INSERT INTO _tmp_table VALUES ('a'), ('b'), ('b'), ('c'), ('c'), ('c') "
3289+ );
3290+
3291+ $ result = $ this ->assertQuery (
3292+ 'SELECT name, COUNT(*) as count FROM _tmp_table GROUP BY name HAVING COUNT(*) > 1 '
3293+ );
3294+ $ this ->assertEquals (
3295+ array (
3296+ (object ) array (
3297+ 'name ' => 'b ' ,
3298+ 'count ' => '2 ' ,
3299+ ),
3300+ (object ) array (
3301+ 'name ' => 'c ' ,
3302+ 'count ' => '3 ' ,
3303+ ),
3304+ ),
3305+ $ result
3306+ );
3307+ }
3308+
3309+ public function testHavingWithoutGroupBy () {
3310+ $ this ->assertQuery (
3311+ 'CREATE TABLE _tmp_table (
3312+ name varchar(20)
3313+ ); '
3314+ );
3315+
3316+ $ this ->assertQuery (
3317+ "INSERT INTO _tmp_table VALUES ('a'), ('b'), ('b'), ('c'), ('c'), ('c') "
3318+ );
3319+
3320+ // HAVING condition satisfied
3321+ $ result = $ this ->assertQuery (
3322+ "SELECT 'T' FROM _tmp_table HAVING COUNT(*) > 1 "
3323+ );
3324+ $ this ->assertEquals (
3325+ array (
3326+ (object ) array (
3327+ ':param0 ' => 'T ' ,
3328+ ),
3329+ ),
3330+ $ result
3331+ );
3332+
3333+ // HAVING condition not satisfied
3334+ $ result = $ this ->assertQuery (
3335+ "SELECT 'T' FROM _tmp_table HAVING COUNT(*) > 100 "
3336+ );
3337+ $ this ->assertEquals (
3338+ array (),
3339+ $ result
3340+ );
3341+
3342+ // DISTINCT ... HAVING, where only some results meet the HAVING condition
3343+ $ result = $ this ->assertQuery (
3344+ 'SELECT DISTINCT name FROM _tmp_table HAVING COUNT(*) > 1 '
3345+ );
3346+ $ this ->assertEquals (
3347+ array (
3348+ (object ) array (
3349+ 'name ' => 'b ' ,
3350+ ),
3351+ (object ) array (
3352+ 'name ' => 'c ' ,
3353+ ),
3354+ ),
3355+ $ result
3356+ );
3357+ }
3358+
31363359 /**
31373360 * @dataProvider mysqlVariablesToTest
31383361 */
0 commit comments