Class ExpressionEvaluatorVisitor
- All Implemented Interfaces:
ExpressionVisitor<Object>
-
Constructor Summary
ConstructorsConstructorDescriptionExpressionEvaluatorVisitor(Table table, Row row, FunctionRegistry functionRegistry, Catalog catalog) -
Method Summary
Modifier and TypeMethodDescriptionThe type name live prints when it refuses an argument, for callers outside the strict-argument walk — the table-function parameter checks name their offending argument the same way.static booleancastMatrixRefuses(DataType source, DataType target) Whether the plain cast refuses outright to carry asourcevalue into a SCALARtarget: the matrix's conversion verdict, the pairsrejectUncastableSource(dev.frostlake.executor.expressions.CastExpression)refuses while a statement compiles.collationOf(Expression expr) The collationexprcarries, and the level it holds it at (seeCollationLevel).booleancountsStoredColumn(Expression argument) Whether a COUNT overargumentis answered from the statistics: over a constant, or over a column that is one of the catalog table's stored columns — a derived relation's too, where it passes one through unchanged.inferStaticRange(Expression expr) The intervalexpr's values lie in, or null when none can be known.inferStaticType(Expression expr) The statically-known type ofexprin this table context, or null when undetermined — the projection-time entry point that gives a derived relation's columns their declared types.voidApplies every function's argument-family refusals to the calls inexprfrom their DECLARED types, before any row is read — the check the row loop makes for each call, brought forward so that an aggregate over an empty table is refused as live refuses it:SELECT AVG(bo) FROM t WHERE FALSEis "Invalid argument types for function 'SUM': (BOOLEAN)" at the call on the account, not NULL.voidA tupleINright-hand list must be parenthesized ROWS of the left side's width.booleanThe predicate behindrequireResolvableFunctionName(dev.frostlake.executor.expressions.FunctionCallExpression), as a question rather than a refusal — the statement-wide scan asks it of every call so it can name them ALL in one sentence, which is what live does.voidInstall the relation a reference's DECLARED type falls back to.voidsetFromClauseKeys(Collection<String> keys) The FROM clause's relation keys — each table's alias when one was written, else its name.voidsetLateralContext(Map<String, Object> lateralContext) voidvoidsetOutputAliasTypes(Map<String, DataType> types) voidsetOutputScopeNames(Set<String> names) Bare names exempt from the plan-time scope rejection — the enclosing query's SELECT output aliases / output column names, which the non-SELECT clauses may legally reference.voidsetQueryExecutor(QueryExecutor queryExecutor) voidsetResultContext(Map<String, Object> resultContext) Provide precomputed SELECT-list outputs (for HAVING / QUALIFY), keyed by the canonical AST form of each select item (viaAstPrinterVisitor) and by its alias.voidPoint this visitor at a new row — lets one visitor be reused across rows (see ExpressionEvaluator).voidsetScopeExemptNames(Set<String> names) voidsetScopeOpaqueToSubqueries(boolean opaque) SeescopeOpaqueToSubqueries.voidsetSubqueryMemo(SubqueryMemo subqueryMemo) voidsetWindowedStrictWalk(boolean windowedStrictWalk) spelledNumber(Expression expr) The NUMBERexprspells when it is a bare string literal, or a column that carries one out of a derived relation, else null — see TableColumn#getSpelledNumber.strictText(dev.frostlake.executor.expressions.Expression)for one of the two calls a NESTING message brackets: a plain AVG at that root is named by its SUM half rather than its whole definition — seeStrictMessagePrinter.averageSumHalf(dev.frostlake.executor.expressions.Expression).strictText(dev.frostlake.executor.expressions.Expression)as an invalid-type sentence quotes an operand: its conversions spelled as the functions the plan made of them,TO_VECTOR(ARRAY_CONSTRUCT(1, 2, 3))andFIXED_TO_FIXED(1 AS NUMBER(10,2)[UNKNOWN])— seeStrictPrintMode.CONVERSION.An arity sentence's echo: the refused call under the name it was written with, its arguments re-printed from the plan asstrictPlanText(dev.frostlake.executor.expressions.Expression)prints them —UPPER(CAST('2020-01-01' AS DATE), 1)forUPPER(TO_DATE('2020-01-01'), 1)andTO_DATE(DATE_ADDDAYSTODATE(1, FT.D), 'YYYY-MM-DD', 1)for a DATEADD beside a format.strictPlanText(Expression expr) strictText(dev.frostlake.executor.expressions.Expression)in the plan-shaped mode — the aggregate, cast and scalar rewrites live's plan applies before it names an operand — for the sentences that re-print an operand from the plan, such as a conversion refusal's parameter.strictText(Expression expr) The expression as a strictness message renders it: live prints the call from its analysed plan, so a column reference comes out qualified with its source relation (TO_VARCHAR(FK.F),CAST(STT.SO AS …)) — seeStrictMessagePrinter.The same sentence for a whole statement's worth of unresolvable calls.voidThe BOOLEAN positions inside a predicate — a searched CASE's WHEN conditions and theBOOLEAN_STRICT_ARGScalls — judged at plan time, so thatWHERE CASE WHEN g THEN TRUE ENDover a VARCHAR refuses over an empty table exactly as it does in a SELECT list.voidvalidateCollations(Expression expr) The collation rules alone, walked over a JOIN's ON condition before any pair of rows is read: AND, OR and NOT are descended, and every comparison, LIKE, IN list and BETWEEN beneath them settles its operands' collations — so two that disagree are refused over tables with no rows, as they are live, rather than surfacing only when a pair happens to be compared.voidvalidateColumnScopeOnly(Expression expression) PHASE ONE of the plan-time walk: every column reference inexpression, nothing else.voidvalidateFunctionNamesOnly(Expression expression) PHASE TWO: every call NAME inexpression, nothing else.voidThe GEOSPATIAL comparison rules alone, walked over a PREDICATE.voidvalidateKeyExpression(Expression expr, SortKeyRole role) Plan-time rejection of a FILE or a GEOSPATIAL value in a GROUPING / SORTING key position.voidThe value an ordering aggregate accumulates may not be semi-structured.voidvalidatePredicateType(Expression predicate) Predicate-position strictness: Snowflake rejects a WHERE, HAVING or QUALIFY condition whose static type is VARCHAR or NUMBER (live: "Invalid data type [VARCHAR(10)] for predicate [STRICT_T.S10]", "[NUMBER(38,0)] for predicate [T.N]", and "[VARCHAR(4)] for predicate ['true']" for a literal).voidvoidThe user-defined function argument check alone, for a FROM-less select item: that path computes the item's value without the strict walk, so the one plan-time refusal it must not miss is run here on its own, before the value is (seerejectUncoercibleUdfArguments(java.lang.String, dev.frostlake.executor.expressions.FunctionCallExpression)).visitCast(CastExpression expr) The bare DML DEFAULT reached EVALUATION, which means it was not standing alone as a value — the write paths take the marker before this.visitFunctionCall(FunctionCallExpression written) visitIn(InExpression expr) visitIsNull(IsNullExpression expr) visitLambda(LambdaExpression expr) visitSpread(SpreadExpression expr) withNarrowingCastEqualitiesAnswered(Expression predicate) A WHERE's or ON's predicate with live's one exemption from the width check applied.
-
Constructor Details
-
ExpressionEvaluatorVisitor
public ExpressionEvaluatorVisitor(Table table, Row row, FunctionRegistry functionRegistry, Catalog catalog)
-
-
Method Details
-
setRow
Point this visitor at a new row — lets one visitor be reused across rows (see ExpressionEvaluator). -
setQueryExecutor
-
setScopeOpaqueToSubqueries
public void setScopeOpaqueToSubqueries(boolean opaque) SeescopeOpaqueToSubqueries. -
setLateralContext
-
setSubqueryMemo
-
setDeclaredTypeBase
Install the relation a reference's DECLARED type falls back to. Only a name this evaluator's own table does not carry at all reaches it: a slot the projection typed answers for itself, and one it could not type stays undetermined rather than borrowing a same-named base column's type.- Parameters:
base- the base relation, or null to clearaliasToTable- its FROM-clause alias map, or nullallTables- its joined relations, or null
-
setMultiTableContext
-
setFromClauseKeys
The FROM clause's relation keys — each table's alias when one was written, else its name. Live, an alias REPLACES the table name: withFROM r AS xthe referencer.tis "invalid identifier 'R.T'" in plain, JOIN and ASOF queries alike, so when these keys are known, a qualifier naming none of them is refused instead of falling through to the bare-name resolution. Null (the default) keeps the historical leniency for paths that do not thread their FROM shape. -
setResultContext
Provide precomputed SELECT-list outputs (for HAVING / QUALIFY), keyed by the canonical AST form of each select item (viaAstPrinterVisitor) and by its alias. A column reference or function call whose canonical form matches resolves to the precomputed value instead of being (re-)evaluated — so an aggregate or window function referenced in a HAVING/QUALIFY condition uses the already-computed result rather than re-aggregating. -
visitDefaultMarker
The bare DML DEFAULT reached EVALUATION, which means it was not standing alone as a value — the write paths take the marker before this. Live agrees exactly here: `SET c = DEFAULT + 1` and `SELECT default FROM t` are both "invalid identifier 'DEFAULT'".- Specified by:
visitDefaultMarkerin interfaceExpressionVisitor<Object>
-
visitLiteral
- Specified by:
visitLiteralin interfaceExpressionVisitor<Object>
-
visitSystemStreamHasData
- Specified by:
visitSystemStreamHasDatain interfaceExpressionVisitor<Object>
-
visitSystemUserTaskCancel
- Specified by:
visitSystemUserTaskCancelin interfaceExpressionVisitor<Object>
-
visitSessionVar
- Specified by:
visitSessionVarin interfaceExpressionVisitor<Object>
-
visitBindVariable
- Specified by:
visitBindVariablein interfaceExpressionVisitor<Object>
-
visitColumnReference
- Specified by:
visitColumnReferencein interfaceExpressionVisitor<Object>
-
visitBinaryOperation
- Specified by:
visitBinaryOperationin interfaceExpressionVisitor<Object>
-
visitUnaryOperation
- Specified by:
visitUnaryOperationin interfaceExpressionVisitor<Object>
-
visitLambda
- Specified by:
visitLambdain interfaceExpressionVisitor<Object>
-
visitFunctionCall
- Specified by:
visitFunctionCallin interfaceExpressionVisitor<Object>
-
unknownFunctionSentence
The same sentence for a whole statement's worth of unresolvable calls. Live names EVERY one of them in a single sentence, pluralising the noun and separating the names with ", " —Unknown functions FNC, FNA, FNB.— and it does NOT de-duplicate: two calls to the same missing name are listed twice.The two families are reported SEPARATELY and never mixed. When a statement carries both a bare unresolvable name and a qualified one, live names only the BARE list; the qualified sentence appears only when every unresolvable call is qualified (live-verified in both directions).
-
resolvesToAFunction
The predicate behindrequireResolvableFunctionName(dev.frostlake.executor.expressions.FunctionCallExpression), as a question rather than a refusal — the statement-wide scan asks it of every call so it can name them ALL in one sentence, which is what live does.- Parameters:
call- the call to judge- Returns:
- whether some path could resolve this name
-
visitCaseExpression
- Specified by:
visitCaseExpressionin interfaceExpressionVisitor<Object>
-
visitCast
- Specified by:
visitCastin interfaceExpressionVisitor<Object>
-
withNarrowingCastEqualitiesAnswered
A WHERE's or ON's predicate with live's one exemption from the width check applied. An equality between a narrowing string cast of a text value and a constant that fits the width can only hold when the value fits too, so live answers it without converting (false for a longer value), where every other use of the cast refuses the value. The cast is dropped from such an equality, either way round, and from an IN list every item of which fits; the walk goes through AND and OR, never under NOT (live-verified).- Parameters:
predicate- the parsed predicate- Returns:
- the predicate with those casts dropped, or the predicate itself when none applies
-
visitIsNull
- Specified by:
visitIsNullin interfaceExpressionVisitor<Object>
-
visitTupleIn
- Specified by:
visitTupleInin interfaceExpressionVisitor<Object>
-
visitSpread
- Specified by:
visitSpreadin interfaceExpressionVisitor<Object>
-
validateUdfArguments
The user-defined function argument check alone, for a FROM-less select item: that path computes the item's value without the strict walk, so the one plan-time refusal it must not miss is run here on its own, before the value is (seerejectUncoercibleUdfArguments(java.lang.String, dev.frostlake.executor.expressions.FunctionCallExpression)). -
validateStrictArguments
-
validateBooleanPositions
The BOOLEAN positions inside a predicate — a searched CASE's WHEN conditions and theBOOLEAN_STRICT_ARGScalls — judged at plan time, so thatWHERE CASE WHEN g THEN TRUE ENDover a VARCHAR refuses over an empty table exactly as it does in a SELECT list. Deliberately only those two rules: the predicate walk stays narrow (seeExpressionEvaluator.validatePredicate), and the full strict walk runs them on its own. -
validatePredicateType
Predicate-position strictness: Snowflake rejects a WHERE, HAVING or QUALIFY condition whose static type is VARCHAR or NUMBER (live: "Invalid data type [VARCHAR(10)] for predicate [STRICT_T.S10]", "[NUMBER(38,0)] for predicate [T.N]", and "[VARCHAR(4)] for predicate ['true']" for a literal). BOOLEAN, VARIANT and undetermined types pass. The three clauses share the sentence, and the predicate is spelled from the plan:MAX(RT.G),COUNT(*),RT.N + 1, a window call in its canonical form, a SELECT alias bare (GG). -
strictText
The expression as a strictness message renders it: live prints the call from its analysed plan, so a column reference comes out qualified with its source relation (TO_VARCHAR(FK.F),CAST(STT.SO AS …)) — seeStrictMessagePrinter. -
strictPlanText
strictText(dev.frostlake.executor.expressions.Expression)in the plan-shaped mode — the aggregate, cast and scalar rewrites live's plan applies before it names an operand — for the sentences that re-print an operand from the plan, such as a conversion refusal's parameter. -
strictPlanCallText
An arity sentence's echo: the refused call under the name it was written with, its arguments re-printed from the plan asstrictPlanText(dev.frostlake.executor.expressions.Expression)prints them —UPPER(CAST('2020-01-01' AS DATE), 1)forUPPER(TO_DATE('2020-01-01'), 1)andTO_DATE(DATE_ADDDAYSTODATE(1, FT.D), 'YYYY-MM-DD', 1)for a DATEADD beside a format. -
strictConversionText
strictText(dev.frostlake.executor.expressions.Expression)as an invalid-type sentence quotes an operand: its conversions spelled as the functions the plan made of them,TO_VECTOR(ARRAY_CONSTRUCT(1, 2, 3))andFIXED_TO_FIXED(1 AS NUMBER(10,2)[UNKNOWN])— seeStrictPrintMode.CONVERSION. -
strictAggregateText
strictText(dev.frostlake.executor.expressions.Expression)for one of the two calls a NESTING message brackets: a plain AVG at that root is named by its SUM half rather than its whole definition — seeStrictMessagePrinter.averageSumHalf(dev.frostlake.executor.expressions.Expression). -
setWindowedStrictWalk
public void setWindowedStrictWalk(boolean windowedStrictWalk) -
validateGeoComparisons
The GEOSPATIAL comparison rules alone, walked over a PREDICATE. The strict-argument walk covers a projection; a WHERE clause is validated byvalidatePredicateType(dev.frostlake.executor.expressions.Expression)instead, and that is exactly whereg = …gets written — so the two comparison rules are applied here as well, and nothing else is. The walk descends only through the containers a comparison nests in. -
rejectInvalidTupleInShape
A tupleINright-hand list must be parenthesized ROWS of the left side's width. The FLAT spelling(a, b) IN (1, 2)is a type error naming the ROW and every scalar — live, "Invalid argument types for function 'IN': (ROW(NUMBER(1,0), NUMBER(1,0)), NUMBER(1,0), NUMBER(1,0))" — and a row of the wrong WIDTH is a conversion error naming both ROW types — live, "Can not convert parameter 'ROW(1, 2, 3)' of type [ROW(NUMBER(1,0), NUMBER(1,0), NUMBER(1,0))] into expected type [ROW(NUMBER(1,0), NUMBER(1,0))]". -
validateOrderedValueExpression
The value an ordering aggregate accumulates may not be semi-structured. This is the same ruleSemiStructuredRejection.INCOMPATIBLE_TYPEScovers forMEDIAN's argument, applied where the value arrives through aWITHIN GROUP (ORDER BY …)clause instead of the argument list: live,PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY o)is "incompatible types: [OBJECT] and [NUMBER(9,0)]" (SQLSTATE 42846) — exactly whatMEDIAN(o)says — while… (ORDER BY n)over a NUMBER is fine.It cannot be declared on the function like the argument positions are, because the clause is not an argument: the FRACTION is, and that position refuses a semi-structured value with the OTHER message ("Invalid argument types for function 'PERCENTILE_CONT': (OBJECT)", live-verified for
PERCENTILE_CONT(o) WITHIN GROUP (ORDER BY n)). One call, two message shapes.A FILE arrives at the same sentence: live, both
PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY f)and thePERCENTILE_DISCspelling are "incompatible types: [FILE] and [NUMBER(9,0)]" — the CLAUSE message, not the "cannot be used as ORDER BY keys" one a bareORDER BY fgets, which is why this check runs before the key rule reaches the clause. -
validateKeyExpression
Plan-time rejection of a FILE or a GEOSPATIAL value in a GROUPING / SORTING key position. A FILE compares, groups as a DISTINCT value and joins perfectly well — live,f = f,SELECT DISTINCT f,COUNT(DISTINCT f),JOIN ON a.f = b.fandf IN (…)are all accepted — but it may not be a GROUP BY, ORDER BY or window PARTITION BY key. The check reads the key's INFERRED type, so it fires for a bare column, a positional ordinal, a SELECT alias and any expression that yields a FILE (GROUP BY IFF(TRUE, f, f)) alike.GEOGRAPHY and GEOMETRY are refused in the same three positions with the same sentence and the same SQLSTATE, measured on a table carrying both:
GROUP BY gis "Expressions of type GEOGRAPHY cannot be used as GROUP BY keys" (42804, vendor 92102),ORDER BY gthe ORDER BY variant (92103) andOVER (PARTITION BY g)the PARTITION BY one (92104) — the three codes FILE uses. Every spelling the FILE rule covers rejects too: the ordinal (GROUP BY 1over a projected geo column), the SELECT alias,ROLLUP(g),CUBE(gm),GROUPING SETS ((g)), a multi-key list,IFF(TRUE, g, g), the ORDER BY inside an OVER spec, a derived table's ORDER BY and the CTE spelling — and all of them on an EMPTY input. Frostlake used to group and sort geo values by their GeoJSON text.This is where geo diverges MOST sharply from the semi-structured types the same machinery serves: live GROUPS, ORDERS and PARTITIONS an OBJECT, an ARRAY and every structured kind quite happily, which is why #143 correctly refused to route those through here. A geo value is nevertheless still a DISTINCT value —
SELECT DISTINCT g,SELECT DISTINCT g, gm,COUNT(DISTINCT g),UNION,INTERSECTandEXCEPTall work live, and none of them routes through this check. -
castMatrixRefuses
Whether the plain cast refuses outright to carry asourcevalue into a SCALARtarget: the matrix's conversion verdict, the pairsrejectUncastableSource(dev.frostlake.executor.expressions.CastExpression)refuses while a statement compiles. A target outside the matrix (a text, a VARIANT, a container) is never refused here.- Parameters:
source- the value's static typetarget- the type it would be cast to- Returns:
- true when no cast from the one to the other exists
-
argumentTypeText
The type name live prints when it refuses an argument, for callers outside the strict-argument walk — the table-function parameter checks name their offending argument the same way. -
countsStoredColumn
Whether a COUNT overargumentis answered from the statistics: over a constant, or over a column that is one of the catalog table's stored columns — a derived relation's too, where it passes one through unchanged. Live answers COUNT(c) and COUNT(1) from them and scans for COUNT(c + 1), COUNT(ABS(c)) and COUNT(c::NUMBER(10,1)); an IFF over a constant condition counts as the branch it folds to.- Parameters:
argument- the COUNT's one argument- Returns:
- true when the statistics answer it
-
inferStaticRange
The intervalexpr's values lie in, or null when none can be known. Never throws. -
rejectArgumentFamilies
Applies every function's argument-family refusals to the calls inexprfrom their DECLARED types, before any row is read — the check the row loop makes for each call, brought forward so that an aggregate over an empty table is refused as live refuses it:SELECT AVG(bo) FROM t WHERE FALSEis "Invalid argument types for function 'SUM': (BOOLEAN)" at the call on the account, not NULL. A call the registry does not know is left to its own refusal.- Parameters:
expr- the expression to walk; window calls are the window stage's own business
-
validateColumnScopeOnly
PHASE ONE of the plan-time walk: every column reference inexpression, nothing else. -
validateFunctionNamesOnly
PHASE TWO: every call NAME inexpression, nothing else. -
setOutputScopeNames
Bare names exempt from the plan-time scope rejection — the enclosing query's SELECT output aliases / output column names, which the non-SELECT clauses may legally reference. -
setOutputAliasTypes
-
setScopeExemptNames
-
inferStaticType
The statically-known type ofexprin this table context, or null when undetermined — the projection-time entry point that gives a derived relation's columns their declared types.Reads the semi-structured refinement where the general inference says only VARIANT, because that is what a derived column's type IS: live,
SYSTEM$TYPEOFover(SELECT OBJECT_CONSTRUCT('a',1) AS x FROM t)reports OBJECT, over(SELECT ARRAY_AGG(n) AS x ...)reports ARRAY and over(SELECT CASE WHEN TRUE THEN o ELSE o END AS x ...)reports OBJECT — whilePARSE_JSON,TO_VARIANTand colon-path access all report VARIANT and are left alone. So the OBJECT/ARRAY producers this refinement knows are exactly the ones live names. -
spelledNumber
The NUMBERexprspells when it is a bare string literal, or a column that carries one out of a derived relation, else null — see TableColumn#getSpelledNumber.- Parameters:
expr- a select item- Returns:
- the measured NUMBER, or null
-
visitWindowFunction
- Specified by:
visitWindowFunctionin interfaceExpressionVisitor<Object>
-
visitObjectAccess
- Specified by:
visitObjectAccessin interfaceExpressionVisitor<Object>
-
visitArrayAccess
- Specified by:
visitArrayAccessin interfaceExpressionVisitor<Object>
-
visitSubquery
- Specified by:
visitSubqueryin interfaceExpressionVisitor<Object>
-
visitExecuteImmediate
- Specified by:
visitExecuteImmediatein interfaceExpressionVisitor<Object>
-
visitJsonObject
- Specified by:
visitJsonObjectin interfaceExpressionVisitor<Object>
-
visitJsonArray
- Specified by:
visitJsonArrayin interfaceExpressionVisitor<Object>
-
visitLikeAnyAll
- Specified by:
visitLikeAnyAllin interfaceExpressionVisitor<Object>
-
visitBetween
- Specified by:
visitBetweenin interfaceExpressionVisitor<Object>
-
visitIn
- Specified by:
visitInin interfaceExpressionVisitor<Object>
-
visitQuantifiedComparison
- Specified by:
visitQuantifiedComparisonin interfaceExpressionVisitor<Object>
-
visitInterval
- Specified by:
visitIntervalin interfaceExpressionVisitor<Object>
-
collationOf
The collationexprcarries, and the level it holds it at (seeCollationLevel). Live-verified, construct by construct:x COLLATE 'spec', COLLATE(x, 'spec') the spec, EXPLICIT; the outermost wins, and COLLATE '' or a bare NULL operand carries none a collated column its declared collation, COLUMN a || b, CONCAT, CONCAT_WS, GREATEST, LEAST, DECODE's and a CASE's results the operands', settled left to right COALESCE, NVL, IFNULL, IFF's and NVL2's results the same, settled from the LAST one back UPPER, LOWER, TRIM, SUBSTR, LEFT, MAX the first argument's a cast, TO_VARCHAR, REPLACE, REPEAT, a literal, anything else noneTwo collations that disagree at one level are the compilation error
ExpressionCollation.combine(dev.frostlake.executor.expressions.ExpressionCollation, dev.frostlake.executor.expressions.ExpressionCollation)raises, so asking an expression for its collation also judges it — which is how the static channel refuses them over any number of rows.- Parameters:
expr- the expression- Returns:
- its collation
-
validateCollations
The collation rules alone, walked over a JOIN's ON condition before any pair of rows is read: AND, OR and NOT are descended, and every comparison, LIKE, IN list and BETWEEN beneath them settles its operands' collations — so two that disagree are refused over tables with no rows, as they are live, rather than surfacing only when a pair happens to be compared.- Parameters:
expr- the condition
-