@@ -245,6 +245,110 @@ public function testWhereExpression(): void
245
245
], $ this ->q ('employee ' )->where ('retired ' , true )->where ($ this ->q ()->expr ('{}=[] or {}=[] ' , ['surname ' , 'Williams ' , 'surname ' , 'Smith ' ]))->getRows ());
246
246
}
247
247
248
+ /**
249
+ * @dataProvider provideWhereNumericCompareCases
250
+ *
251
+ * @param array{string, array<mixed>} $exprLeft
252
+ * @param array{string, array<mixed>} $exprRight
253
+ */
254
+ public function testWhereNumericCompare (array $ exprLeft , string $ operator , array $ exprRight , bool $ expectPostgresqlTypeMismatchException = false , bool $ expectMssqlTypeMismatchException = false , bool $ expectSqliteWrongResult = false ): void
255
+ {
256
+ $ queryWhere = $ this ->q ()->field ($ this ->e ('1 ' ), 'v ' );
257
+ if ($ this ->getDatabasePlatform () instanceof MySQLPlatform) {
258
+ $ queryWhere ->table ('(select 1) ' , 'dual ' ); // needed for MySQL 5.x when WHERE or HAVING is specified
259
+ }
260
+ $ queryWhere ->where ($ this ->e (...$ exprLeft ), $ operator , $ this ->e (...$ exprRight ));
261
+
262
+ $ queryHaving = $ this ->q ()->field ($ this ->e ('1 ' ), 'v ' );
263
+ if ($ this ->getDatabasePlatform () instanceof MySQLPlatform) {
264
+ $ queryHaving ->table ('(select 1) ' , 'dual ' ); // needed for MySQL 5.x when WHERE or HAVING is specified
265
+ }
266
+ if ($ this ->getDatabasePlatform () instanceof SQLitePlatform) {
267
+ $ queryHaving ->group ('v ' );
268
+ }
269
+ $ queryHaving ->having ($ this ->e (...$ exprLeft ), $ operator , $ this ->e (...$ exprRight ));
270
+
271
+ $ queryWhere2 = $ this ->q ()->field ($ this ->e ('1 ' ), 'v ' );
272
+ $ queryWhere2 ->table ($ this ->q ()->field ($ this ->e (...$ exprLeft ), 'a ' )->field ($ this ->e (...$ exprRight ), 'b ' ), 't ' );
273
+ $ queryWhere2 ->where ('a ' , $ operator , $ this ->e ('{} ' , ['b ' ]));
274
+
275
+ $ queryAll = $ this ->q ()
276
+ ->field ($ queryWhere , 'where ' )
277
+ ->field ($ queryHaving , 'having ' )
278
+ ->field ($ queryWhere2 , 'where2 ' );
279
+
280
+ if (($ expectPostgresqlTypeMismatchException && $ this ->getDatabasePlatform () instanceof PostgreSQLPlatform) || ($ expectMssqlTypeMismatchException && $ this ->getDatabasePlatform () instanceof SQLServerPlatform)) {
281
+ $ this ->expectException (ExecuteException::class);
282
+ }
283
+ try {
284
+ $ rows = $ queryAll ->getRows ();
285
+ } catch (ExecuteException $ e ) {
286
+ if ($ expectPostgresqlTypeMismatchException && $ this ->getDatabasePlatform () instanceof PostgreSQLPlatform && str_contains ($ e ->getPrevious ()->getMessage (), 'operator does not exist ' )) {
287
+ // https://dbfiddle.uk/YJvvOTpR
288
+ self ::markTestIncomplete ('PostgreSQL does not implicitly cast string for numeric comparison ' );
289
+ } elseif ($ expectMssqlTypeMismatchException && $ this ->getDatabasePlatform () instanceof SQLServerPlatform && str_contains ($ e ->getPrevious ()->getMessage (), 'Conversion failed when converting the nvarchar value \'4.0 \' to data type int ' )) {
290
+ // https://dbfiddle.uk/YmYeklp_
291
+ self ::markTestIncomplete ('MSSQL does not implicitly cast string with decimal point for float comparison ' );
292
+ }
293
+
294
+ throw $ e ;
295
+ }
296
+
297
+ self ::assertSame (
298
+ $ expectSqliteWrongResult && $ this ->getDatabasePlatform () instanceof SQLitePlatform
299
+ ? [['where ' => null , 'having ' => null , 'where2 ' => null ]]
300
+ : [['where ' => '1 ' , 'having ' => '1 ' , 'where2 ' => '1 ' ]],
301
+ $ rows
302
+ );
303
+ }
304
+
305
+ /**
306
+ * @return iterable<list<mixed>>
307
+ */
308
+ public function provideWhereNumericCompareCases (): iterable
309
+ {
310
+ yield [['4 ' ], '= ' , ['4 ' ]];
311
+ yield [['0 ' ], '= ' , ['0 ' ]];
312
+ yield [['4 ' ], '< ' , ['5 ' ]];
313
+ yield [['5 ' ], '> ' , ['4 ' ]];
314
+ yield [['\'4 \'' ], '= ' , ['\'4 \'' ]];
315
+ yield [['\'04 \'' ], '= ' , ['\'04 \'' ]];
316
+ yield [['\'4 \'' ], '!= ' , ['\'04 \'' ]];
317
+ yield [['\'4 \'' ], '!= ' , ['\'4.0 \'' ]];
318
+ yield [['4.4 ' ], '= ' , ['4.4 ' ]];
319
+ yield [['0.0 ' ], '= ' , ['0.0 ' ]];
320
+ yield [['4.4 ' ], '!= ' , ['4.3 ' ]];
321
+
322
+ yield [['4 ' ], '= ' , ['[] ' , [4 ]]];
323
+ yield [['0 ' ], '= ' , ['[] ' , [0 ]]];
324
+ yield [['\'4 \'' ], '= ' , ['[] ' , ['4 ' ]]];
325
+ yield [['\'04 \'' ], '= ' , ['[] ' , ['04 ' ]]];
326
+ yield [['\'4 \'' ], '!= ' , ['[] ' , ['04 ' ]]];
327
+ yield [['\'4 \'' ], '!= ' , ['[] ' , ['4.0 ' ]]];
328
+ yield [['4.4 ' ], '= ' , ['[] ' , [4.4 ]], false , false , true ];
329
+ yield [['0.0 ' ], '= ' , ['[] ' , [0.0 ]], false , false , true ];
330
+ yield [['4.4 ' ], '!= ' , ['[] ' , [4.3 ]]];
331
+ yield [['4e1 ' ], '= ' , ['[] ' , [40.0 ]], false , false , true ];
332
+
333
+ yield [['[] ' , [4 ]], '= ' , ['[] ' , [4 ]]];
334
+ yield [['[] ' , ['4 ' ]], '= ' , ['[] ' , ['4 ' ]]];
335
+ yield [['[] ' , [4.4 ]], '= ' , ['[] ' , [4.4 ]]];
336
+ yield [['[] ' , [4.4 ]], '> ' , ['[] ' , [4.3 ]]];
337
+ yield [['[] ' , [true ]], '= ' , ['[] ' , [true ]]];
338
+ yield [['[] ' , [false ]], '= ' , ['[] ' , [false ]]];
339
+
340
+ yield [['4 ' ], '= ' , ['[] ' , ['04 ' ]], true , false , true ];
341
+ yield [['\'04 \'' ], '= ' , ['[] ' , [4 ]], true , false , true ];
342
+ yield [['4 ' ], '= ' , ['[] ' , [4.0 ]], false , true , true ];
343
+ yield [['4 ' ], '= ' , ['[] ' , ['4.0 ' ]], true , true , true ];
344
+ yield [['2.5 ' ], '= ' , ['[] ' , ['02.50 ' ]], true , false , true ];
345
+
346
+ yield [['2 + 2 ' ], '= ' , ['[] ' , [4 ]]];
347
+ yield [['2 + 2 ' ], '= ' , ['[] ' , ['4 ' ]], true , false , true ];
348
+ yield [['2 + 2.5 ' ], '= ' , ['[] ' , [4.5 ]], false , false , true ];
349
+ yield [['2 + 2.5 ' ], '= ' , ['[] ' , ['4.5 ' ]], true , false , true ];
350
+ }
351
+
248
352
public function testGroupConcat (): void
249
353
{
250
354
$ q = $ this ->q ()
0 commit comments