| 340 | } |
| 341 | |
| 342 | ExprPtr tryFoldIfConstant(const ExprPtr& expr, Scope* scope) { |
| 343 | if (expr->isConstant() && scope->exprSet->execCtx()) { |
| 344 | try { |
| 345 | auto rowType = ROW({}, {}); |
| 346 | auto execCtx = scope->exprSet->execCtx(); |
| 347 | auto row = BaseVector::create(rowType, 1, execCtx->pool()); |
| 348 | EvalCtx context( |
| 349 | execCtx, scope->exprSet, dynamic_cast<RowVector*>(row.get())); |
| 350 | VectorPtr result; |
| 351 | SelectivityVector rows(1); |
| 352 | expr->eval(rows, context, result); |
| 353 | auto constantVector = BaseVector::wrapInConstant(1, 0, result); |
| 354 | |
| 355 | return std::make_shared<ConstantExpr>(constantVector); |
| 356 | } |
| 357 | // Constant folding has a subtle gotcha: if folding a constant expression |
| 358 | // deterministically throws, we can't throw at expression compilation time |
| 359 | // yet because we can't guarantee that this expression would actually need |
| 360 | // to be evaluated. |
| 361 | // |
| 362 | // So, here, if folding an expression throws an exception, we just ignore it |
| 363 | // and leave the expression as-is. If this expression is hit at execution |
| 364 | // time and needs to be evaluated, it will throw and fail the query anyway. |
| 365 | // If not, in case this expression is never hit at execution time (for |
| 366 | // instance, if other arguments are all null in a function with default null |
| 367 | // behavior), the query won't fail. |
| 368 | catch (const BoltUserError&) { |
| 369 | } |
| 370 | } |
| 371 | return expr; |
| 372 | } |
| 373 | |
| 374 | /// Returns a vector aligned with exprs vector where elements that correspond to |
| 375 | /// constant expressions are set to constant values of these expressions. |
no test coverage detected