|
11 | 11 | use Vimeo\MysqlEngine\Query\Expression\FunctionExpression;
|
12 | 12 | use Vimeo\MysqlEngine\Query\Expression\IntervalOperatorExpression;
|
13 | 13 | use Vimeo\MysqlEngine\Schema\Column;
|
| 14 | +use Vimeo\MysqlEngine\TokenType; |
14 | 15 |
|
15 | 16 | final class FunctionEvaluator
|
16 | 17 | {
|
@@ -91,6 +92,11 @@ public static function evaluate(
|
91 | 92 | return self::sqlDateAdd($conn, $scope, $expr, $row, $result);
|
92 | 93 | case 'ROUND':
|
93 | 94 | return self::sqlRound($conn, $scope, $expr, $row, $result);
|
| 95 | + case 'CEIL': |
| 96 | + case 'CEILING': |
| 97 | + return self::sqlCeiling($conn, $scope, $expr, $row, $result); |
| 98 | + case 'FLOOR': |
| 99 | + return self::sqlFloor($conn, $scope, $expr, $row, $result); |
94 | 100 | case 'DATEDIFF':
|
95 | 101 | return self::sqlDateDiff($conn, $scope, $expr, $row, $result);
|
96 | 102 | case 'DAY':
|
@@ -138,8 +144,34 @@ public static function getColumnSchema(
|
138 | 144 |
|
139 | 145 | case 'MOD':
|
140 | 146 | return new Column\IntColumn(false, 10);
|
| 147 | + |
141 | 148 | case 'AVG':
|
142 | 149 | return new Column\FloatColumn(10, 2);
|
| 150 | + |
| 151 | + case 'CEIL': |
| 152 | + case 'CEILING': |
| 153 | + case 'FLOOR': |
| 154 | + // from MySQL docs: https://dev.mysql.com/doc/refman/5.6/en/mathematical-functions.html#function_ceil |
| 155 | + // For exact-value numeric arguments, the return value has an exact-value numeric type. For string or |
| 156 | + // floating-point arguments, the return value has a floating-point type. But... |
| 157 | + // |
| 158 | + // mysql> CREATE TEMPORARY TABLE `temp` SELECT FLOOR(1.2); |
| 159 | + // Query OK, 1 row affected (0.00 sec) |
| 160 | + // Records: 1 Duplicates: 0 Warnings: 0 |
| 161 | + // |
| 162 | + // mysql> describe temp; |
| 163 | + // +------------+--------+------+-----+---------+-------+ |
| 164 | + // | Field | Type | Null | Key | Default | Extra | |
| 165 | + // +------------+--------+------+-----+---------+-------+ |
| 166 | + // | FLOOR(1.2) | bigint | NO | | 0 | NULL | |
| 167 | + // +------------+--------+------+-----+---------+-------+ |
| 168 | + // 1 row in set (0.00 sec) |
| 169 | + if ($expr->args[0]->getType() == TokenType::STRING_CONSTANT) { |
| 170 | + return new Column\DoubleColumn(10, 2); |
| 171 | + } |
| 172 | + |
| 173 | + return new Column\BigInt(false, 10); |
| 174 | + |
143 | 175 | case 'IF':
|
144 | 176 | $if = Evaluator::getColumnSchema($expr->args[1], $scope, $columns);
|
145 | 177 | $else = Evaluator::getColumnSchema($expr->args[2], $scope, $columns);
|
@@ -1377,6 +1409,72 @@ private static function sqlInetNtoa(
|
1377 | 1409 | return long2ip((int)$subject);
|
1378 | 1410 | }
|
1379 | 1411 |
|
| 1412 | + /** |
| 1413 | + * @param array<string, mixed> $row |
| 1414 | + * @return float|0 |
| 1415 | + */ |
| 1416 | + private static function sqlCeiling( |
| 1417 | + FakePdoInterface $conn, |
| 1418 | + Scope $scope, |
| 1419 | + FunctionExpression $expr, |
| 1420 | + array $row, |
| 1421 | + QueryResult $result |
| 1422 | + ) { |
| 1423 | + $args = $expr->args; |
| 1424 | + |
| 1425 | + if (\count($args) !== 1) { |
| 1426 | + throw new ProcessorException("MySQL CEILING function must be called with one argument (got " . count($args) . ")"); |
| 1427 | + } |
| 1428 | + |
| 1429 | + $subject = Evaluator::evaluate($conn, $scope, $args[0], $row, $result); |
| 1430 | + |
| 1431 | + if (!is_numeric($subject)) { |
| 1432 | + // CEILING() returns 0 if it does not understand its argument. |
| 1433 | + return 0; |
| 1434 | + } |
| 1435 | + |
| 1436 | + $value = ceil(floatval($subject)); |
| 1437 | + |
| 1438 | + if (!$value) { |
| 1439 | + return 0; |
| 1440 | + } |
| 1441 | + |
| 1442 | + return $value; |
| 1443 | + } |
| 1444 | + |
| 1445 | + /** |
| 1446 | + * @param array<string, mixed> $row |
| 1447 | + * @return float|0 |
| 1448 | + */ |
| 1449 | + private static function sqlFloor( |
| 1450 | + FakePdoInterface $conn, |
| 1451 | + Scope $scope, |
| 1452 | + FunctionExpression $expr, |
| 1453 | + array $row, |
| 1454 | + QueryResult $result |
| 1455 | + ) { |
| 1456 | + $args = $expr->args; |
| 1457 | + |
| 1458 | + if (\count($args) !== 1) { |
| 1459 | + throw new ProcessorException("MySQL FLOOR function must be called with one argument"); |
| 1460 | + } |
| 1461 | + |
| 1462 | + $subject = Evaluator::evaluate($conn, $scope, $args[0], $row, $result); |
| 1463 | + |
| 1464 | + if (!is_numeric($subject)) { |
| 1465 | + // FLOOR() returns 0 if it does not understand its argument. |
| 1466 | + return 0; |
| 1467 | + } |
| 1468 | + |
| 1469 | + $value = floor(floatval($subject)); |
| 1470 | + |
| 1471 | + if (!$value) { |
| 1472 | + return 0; |
| 1473 | + } |
| 1474 | + |
| 1475 | + return $value; |
| 1476 | + } |
| 1477 | + |
1380 | 1478 | private static function getPhpIntervalFromExpression(
|
1381 | 1479 | FakePdoInterface $conn,
|
1382 | 1480 | Scope $scope,
|
|
0 commit comments