Skip to content

Commit

Permalink
change missing propagation logic
Browse files Browse the repository at this point in the history
  • Loading branch information
yliuuuu committed Nov 28, 2023
1 parent 5eca534 commit 0b3925f
Show file tree
Hide file tree
Showing 15 changed files with 314 additions and 341 deletions.
190 changes: 124 additions & 66 deletions partiql-planner/src/main/kotlin/org/partiql/planner/PartiQLHeader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ object PartiQLHeader : Header() {
* PartiQL Scalar Functions accessible via special form syntax (unary, binary, infix keywords, etc).
*/
override val operators = listOf(
logical(),
predicate(),
operators(),
special(),
system(),
Expand All @@ -52,16 +54,8 @@ object PartiQLHeader : Header() {
* Generate all unary and binary operator signatures.
*/
private fun operators(): List<FunctionSignature.Scalar> = listOf(
not(),
pos(),
neg(),
eq(),
and(),
or(),
lt(),
lte(),
gt(),
gte(),
plus(),
minus(),
times(),
Expand All @@ -71,6 +65,61 @@ object PartiQLHeader : Header() {
bitwiseAnd(),
).flatten()

/**
* Predicate function -- Condition that can be evaluated to a boolean value.
*
* Predicate function IS NULL, IS MISSING, `=`(Equal) does not propagate `MISSING`.
*/
private fun predicate(): List<FunctionSignature.Scalar> = listOf(
// SQL
// 8.2 - comparison predicate
lt(),
lte(),
gt(),
gte(),
eq(),

// 8.3 - between predicate
between(),
// 8.4 - in predicate
inCollection(),
// 8.5 - like predicate
like(),
// 8.7 - null predicate
isNull(),

// PartiQL
isMissing(), // missing predication
isType(), // type predicate
isTypeSingleArg(),
isTypeDoubleArgsInt(),
isTypeTime(),
).flatten()

/**
* Logical functions follows the three-valued logic truth table:
*
* |A |B |A AND B|A OR B |NOT A |
* |----|----|-------|-------|------|
* |T |T |T |T |F |
* |T |F |F |T |F |
* |T |U |U |T |F |
* |F |T |F |T |T |
* |F |F |F |F |T |
* |F |U |F |U |T |
* |U |T |U |T |U |
* |U |F |F |U |U |
* |U |U |U |U |U |
*
* 1. The `MISSING` value, when convert to a truth value, becomes a `UNKNOWN`.
* 2. `UNKNOWN` truth value, when converting to PartiQL Value, becomes NULL of boolean type.
*/
private fun logical(): List<FunctionSignature.Scalar> = listOf(
not(),
and(),
or(),
).flatten()

/**
* SQL Builtins (not special forms)
*/
Expand All @@ -87,14 +136,6 @@ object PartiQLHeader : Header() {
* SQL and PartiQL special forms
*/
private fun special(): List<FunctionSignature.Scalar> = listOf(
like(),
between(),
inCollection(),
isUnknown(),
isType(),
isTypeSingleArg(),
isTypeDoubleArgsInt(),
isTypeTime(),
position(),
substring(),
trimSpecial(),
Expand All @@ -120,15 +161,15 @@ object PartiQLHeader : Header() {
FunctionSignature.Scalar(
name = "not",
returns = BOOL,
isNullCall = false,
isNullable = true,
isNullCall = true,
isNullable = false,
parameters = listOf(FunctionParameter("value", BOOL)),
),
FunctionSignature.Scalar(
name = "not",
returns = BOOL,
isNullCall = false,
isNullable = true,
isNullCall = true,
isNullable = false,
parameters = listOf(FunctionParameter("value", MISSING)),
),
)
Expand Down Expand Up @@ -335,78 +376,95 @@ object PartiQLHeader : Header() {
}
}.flatten()

// To model type assertion, generating a list of assertion function based on the type,
// and the parameter will be the value entered.
// i.e., 1 is INT2 => is_int16(1)
// TODO: We can remove the types with parameter in this function.
// but, leaving out the decision to have, for example:
// is_decimal(null, null, value) vs is_decimal(value) later....
private fun isType(): List<FunctionSignature.Scalar> = types.all.filterNot { it == NULL || it == MISSING }.map { element ->
private fun isNull(): List<FunctionSignature.Scalar> = listOf(
FunctionSignature.Scalar(
name = "is_${element.name.lowercase()}",
name = "is_null",
returns = BOOL,
parameters = listOf(
FunctionParameter("value", ANY) // TODO: Decide if we need to further segment this
),
isNullCall = false,
isNullable = false
)
}
)

private fun isUnknown(): List<FunctionSignature.Scalar> = listOf(MISSING, NULL).map { element ->
private fun isMissing(): List<FunctionSignature.Scalar> = listOf(
FunctionSignature.Scalar(
name = "is_${element.name.lowercase()}",
name = "is_missing",
returns = BOOL,
parameters = listOf(
FunctionParameter("value", ANY) // TODO: Decide if we need to further segment this
),
isNullCall = false,
isNullable = false
)
)

// To model type assertion, generating a list of assertion function based on the type,
// and the parameter will be the value entered.
// i.e., 1 is INT2 => is_int16(1)
private fun isType(): List<FunctionSignature.Scalar> = types.all.filterNot { it == NULL || it == MISSING }.flatMap { element ->
types.all.filterNot { it == MISSING || it == ANY }.map { operand ->
FunctionSignature.Scalar(
name = "is_${element.name.lowercase()}",
returns = BOOL,
parameters = listOf(
FunctionParameter("value", operand)
),
isNullCall = false, // TODO: Should this be true?
isNullable = false
)
}
}

// In type assertion, it is possible for types to have args
// i.e., 'a' is CHAR(2)
// we put type parameter before value.
private fun isTypeSingleArg(): List<FunctionSignature.Scalar> = listOf(CHAR, STRING).map { element ->
FunctionSignature.Scalar(
name = "is_${element.name.lowercase()}",
returns = BOOL,
parameters = listOf(
FunctionParameter("type_parameter_1", INT32),
FunctionParameter("value", ANY) // TODO: Decide if we need to further segment this
),
isNullable = false,
isNullCall = false
)
private fun isTypeSingleArg(): List<FunctionSignature.Scalar> = listOf(CHAR, STRING).flatMap { element ->
types.all.filterNot { it == MISSING }.map { operand ->
FunctionSignature.Scalar(
name = "is_${element.name.lowercase()}",
returns = BOOL,
parameters = listOf(
FunctionParameter("type_parameter_1", INT32),
FunctionParameter("value", operand)
),
isNullable = false, // TODO: Should this be true?
isNullCall = false
)
}
}

private fun isTypeDoubleArgsInt(): List<FunctionSignature.Scalar> = listOf(DECIMAL).map { element ->
FunctionSignature.Scalar(
name = "is_${element.name.lowercase()}",
returns = BOOL,
parameters = listOf(
FunctionParameter("type_parameter_1", INT32),
FunctionParameter("type_parameter_2", INT32),
FunctionParameter("value", ANY) // TODO: Decide if we need to further segment this
),
isNullable = false,
isNullCall = false
)
private fun isTypeDoubleArgsInt(): List<FunctionSignature.Scalar> = listOf(DECIMAL).flatMap { element ->
types.all.filterNot { it == MISSING }.map { operand ->
FunctionSignature.Scalar(
name = "is_${element.name.lowercase()}",
returns = BOOL,
parameters = listOf(
FunctionParameter("type_parameter_1", INT32),
FunctionParameter("type_parameter_2", INT32),
FunctionParameter("value", operand)
),
isNullable = false,
isNullCall = false
)
}
}

private fun isTypeTime(): List<FunctionSignature.Scalar> = listOf(TIME, TIMESTAMP).map { element ->
FunctionSignature.Scalar(
name = "is_${element.name.lowercase()}",
returns = BOOL,
parameters = listOf(
FunctionParameter("type_parameter_1", BOOL),
FunctionParameter("type_parameter_2", INT32),
FunctionParameter("value", ANY) // TODO: Decide if we need to further segment this
),
isNullCall = false,
isNullable = false
)
private fun isTypeTime(): List<FunctionSignature.Scalar> = listOf(TIME, TIMESTAMP).flatMap { element ->
types.all.filterNot { it == MISSING }.map { operand ->
FunctionSignature.Scalar(
name = "is_${element.name.lowercase()}",
returns = BOOL,
parameters = listOf(
FunctionParameter("type_parameter_1", BOOL),
FunctionParameter("type_parameter_2", INT32),
FunctionParameter("value", operand) // TODO: Decide if we need to further segment this
),
isNullCall = false,
isNullable = false
)
}
}

// SUBSTRING (expression, start[, length]?)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ internal class FnResolver(private val headers: List<Header>) {
}
// if all elements requires casting, then no match
// because there must be another function definition that requires no casting
return if (mapping.contains(null) || mapping.isEmpty()) {
return if (mapping.isEmpty() || mapping.contains(null)) {
// we made a match
mapping
} else {
Expand Down
Loading

0 comments on commit 0b3925f

Please sign in to comment.