Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for isNull and isNotNull conditions #529

Merged
merged 2 commits into from
Mar 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@

import com.scalar.db.api.Scan.Ordering.Order;
import com.scalar.db.config.DatabaseConfig;
import com.scalar.db.io.BigIntColumn;
import com.scalar.db.io.BigIntValue;
import com.scalar.db.io.BlobColumn;
import com.scalar.db.io.BlobValue;
import com.scalar.db.io.BooleanColumn;
import com.scalar.db.io.BooleanValue;
import com.scalar.db.io.Column;
import com.scalar.db.io.DataType;
import com.scalar.db.io.DoubleColumn;
import com.scalar.db.io.DoubleValue;
import com.scalar.db.io.FloatColumn;
import com.scalar.db.io.FloatValue;
import com.scalar.db.io.IntColumn;
import com.scalar.db.io.IntValue;
import com.scalar.db.io.TextColumn;
import com.scalar.db.io.TextValue;
import com.scalar.db.io.Value;
import com.scalar.db.storage.cosmos.CosmosAdmin;
Expand Down Expand Up @@ -66,6 +74,35 @@ public static Value<?> getRandomValue(
}
}

public static Column<?> getColumnWithRandomValue(
Random random, String columnName, DataType dataType, boolean allowEmpty) {
switch (dataType) {
case BOOLEAN:
return BooleanColumn.of(columnName, random.nextBoolean());
case INT:
return IntColumn.of(columnName, random.nextInt());
case BIGINT:
return BigIntColumn.of(columnName, nextBigInt(random));
case FLOAT:
return FloatColumn.of(columnName, nextFloat(random));
case DOUBLE:
return DoubleColumn.of(columnName, nextDouble(random));
case TEXT:
int count =
allowEmpty ? random.nextInt(MAX_TEXT_COUNT) : random.nextInt(MAX_TEXT_COUNT - 1) + 1;
return TextColumn.of(
columnName, RandomStringUtils.random(count, 0, 0, true, true, null, random));
case BLOB:
int length =
allowEmpty ? random.nextInt(MAX_BLOB_LENGTH) : random.nextInt(MAX_BLOB_LENGTH - 1) + 1;
byte[] bytes = new byte[length];
random.nextBytes(bytes);
return BlobColumn.of(columnName, bytes);
default:
throw new AssertionError();
}
}

public static long nextBigInt(Random random) {
return random
.longs(BigIntValue.MIN_VALUE, (BigIntValue.MAX_VALUE + 1))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.scalar.db.storage.cassandra;

import com.google.common.collect.Ordering;
import com.scalar.db.api.ConditionalExpression.Operator;
import com.scalar.db.config.DatabaseConfig;
import com.scalar.db.io.Column;
import com.scalar.db.storage.StorageConditionalMutationIntegrationTestBase;

public class CassandraConditionalMutationIntegrationTest
Expand All @@ -9,4 +12,17 @@ public class CassandraConditionalMutationIntegrationTest
protected DatabaseConfig getDatabaseConfig() {
return CassandraEnv.getDatabaseConfig();
}

@Override
protected boolean shouldMutate(
Column<?> initialColumn, Column<?> columnToCompare, Operator operator) {
switch (operator) {
case EQ:
return Ordering.natural().compare(initialColumn, columnToCompare) == 0;
case NE:
return Ordering.natural().compare(initialColumn, columnToCompare) != 0;
default:
return super.shouldMutate(initialColumn, columnToCompare, operator);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ protected List<OperatorAndDataType> getOperatorAndDataTypeListForTest() {
List<OperatorAndDataType> ret = new ArrayList<>();
for (Operator operator : Operator.values()) {
for (DataType dataType : DataType.values()) {
// Cosmos DB only supports the 'equal' and 'not equal' conditions for BLOB type
// Cosmos DB only supports the 'equal' and 'not equal' and 'is null' and 'is not null'
// conditions for BLOB type
if (dataType == DataType.BLOB) {
if (operator == Operator.EQ || operator == Operator.NE) {
if (operator == Operator.EQ
|| operator == Operator.NE
|| operator == Operator.IS_NULL
|| operator == Operator.IS_NOT_NULL) {
ret.add(new OperatorAndDataType(operator, dataType));
}
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.scalar.db.storage.dynamo;

import com.google.common.collect.Ordering;
import com.scalar.db.api.ConditionalExpression.Operator;
import com.scalar.db.config.DatabaseConfig;
import com.scalar.db.io.Column;
import com.scalar.db.io.DataType;
import com.scalar.db.io.Value;
import com.scalar.db.storage.StorageConditionalMutationIntegrationTestBase;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -27,9 +28,13 @@ protected List<OperatorAndDataType> getOperatorAndDataTypeListForTest() {
List<OperatorAndDataType> ret = new ArrayList<>();
for (Operator operator : Operator.values()) {
for (DataType dataType : DataType.values()) {
// DynamoDB only supports the 'equal' and 'not equal' conditions for BOOLEAN type
// DynamoDB only supports the 'equal' and 'not equal' and 'is null' and 'is not null'
// conditions for BOOLEAN type
if (dataType == DataType.BOOLEAN) {
if (operator == Operator.EQ || operator == Operator.NE) {
if (operator == Operator.EQ
|| operator == Operator.NE
|| operator == Operator.IS_NULL
|| operator == Operator.IS_NOT_NULL) {
ret.add(new OperatorAndDataType(operator, dataType));
}
} else {
Expand All @@ -41,10 +46,24 @@ protected List<OperatorAndDataType> getOperatorAndDataTypeListForTest() {
}

@Override
protected Value<?> getRandomValue(Random random, String columnName, DataType dataType) {
protected Column<?> getColumnWithRandomValue(
Random random, String columnName, DataType dataType) {
if (dataType == DataType.DOUBLE) {
return DynamoTestUtils.getRandomDynamoDoubleValue(random, columnName);
return DynamoTestUtils.getRandomDynamoDoubleColumn(random, columnName);
}
return super.getColumnWithRandomValue(random, columnName, dataType);
}

@Override
protected boolean shouldMutate(
Column<?> initialColumn, Column<?> columnToCompare, Operator operator) {
switch (operator) {
case EQ:
return Ordering.natural().compare(initialColumn, columnToCompare) == 0;
case NE:
return Ordering.natural().compare(initialColumn, columnToCompare) != 0;
default:
return super.shouldMutate(initialColumn, columnToCompare, operator);
}
return super.getRandomValue(random, columnName, dataType);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.scalar.db.storage.dynamo;

import com.scalar.db.io.DoubleColumn;
import com.scalar.db.io.DoubleValue;
import java.util.Random;

Expand All @@ -14,6 +15,10 @@ public static DoubleValue getRandomDynamoDoubleValue(Random random, String colum
return new DoubleValue(columnName, nextDynamoDouble(random));
}

public static DoubleColumn getRandomDynamoDoubleColumn(Random random, String columnName) {
return DoubleColumn.of(columnName, nextDynamoDouble(random));
}

public static double nextDynamoDouble(Random random) {
return random
.doubles(MIN_DYNAMO_DOUBLE_VALUE, MAX_DYNAMO_DOUBLE_VALUE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import com.scalar.db.api.ConditionalExpression.Operator;
import com.scalar.db.config.DatabaseConfig;
import com.scalar.db.io.Column;
import com.scalar.db.io.DataType;
import com.scalar.db.io.Value;
import com.scalar.db.storage.StorageConditionalMutationIntegrationTestBase;
import com.scalar.db.storage.TestUtils;
import java.util.ArrayList;
Expand Down Expand Up @@ -42,14 +42,15 @@ protected List<OperatorAndDataType> getOperatorAndDataTypeListForTest() {
}

@Override
protected Value<?> getRandomValue(Random random, String columnName, DataType dataType) {
protected Column<?> getColumnWithRandomValue(
Random random, String columnName, DataType dataType) {
if (rdbEngine == RdbEngine.ORACLE) {
if (dataType == DataType.DOUBLE) {
return JdbcTestUtils.getRandomOracleDoubleValue(random, columnName);
return JdbcTestUtils.getRandomOracleDoubleColumn(random, columnName);
}
// don't allow empty value since Oracle treats empty value as NULL
return TestUtils.getRandomValue(random, columnName, dataType, false);
return TestUtils.getColumnWithRandomValue(random, columnName, dataType, false);
}
return super.getRandomValue(random, columnName, dataType);
return super.getColumnWithRandomValue(random, columnName, dataType);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.scalar.db.storage.jdbc;

import com.scalar.db.io.Column;
import com.scalar.db.io.DoubleColumn;
import com.scalar.db.io.DoubleValue;
import com.scalar.db.io.TextValue;
import com.scalar.db.io.Value;
Expand All @@ -18,6 +20,10 @@ public static Value<?> getRandomOracleDoubleValue(Random random, String columnNa
return new DoubleValue(columnName, nextOracleDouble(random));
}

public static Column<?> getRandomOracleDoubleColumn(Random random, String columnName) {
return DoubleColumn.of(columnName, nextOracleDouble(random));
}

public static double nextOracleDouble(Random random) {
return random
.doubles(MIN_ORACLE_DOUBLE_VALUE, MAX_ORACLE_DOUBLE_VALUE)
Expand Down
133 changes: 133 additions & 0 deletions core/src/main/java/com/scalar/db/api/ConditionBuilder.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package com.scalar.db.api;

import com.scalar.db.api.ConditionalExpression.Operator;
import com.scalar.db.io.BigIntColumn;
import com.scalar.db.io.BlobColumn;
import com.scalar.db.io.BooleanColumn;
import com.scalar.db.io.Column;
import com.scalar.db.io.DoubleColumn;
import com.scalar.db.io.FloatColumn;
import com.scalar.db.io.IntColumn;
import com.scalar.db.io.TextColumn;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -587,6 +594,132 @@ public ConditionalExpression isLessThanOrEqualToBlob(byte[] value) {
public ConditionalExpression isLessThanOrEqualToBlob(ByteBuffer value) {
return new ConditionalExpression(columnName, value, Operator.LTE);
}

/**
* Creates a 'is null' conditional expression for a BOOLEAN value.
*
* @return a conditional expression
*/
public ConditionalExpression isNullBoolean() {
return new ConditionalExpression(BooleanColumn.ofNull(columnName), Operator.IS_NULL);
}

/**
* Creates a 'is null' conditional expression for an INT value.
*
* @return a conditional expression
*/
public ConditionalExpression isNullInt() {
return new ConditionalExpression(IntColumn.ofNull(columnName), Operator.IS_NULL);
}

/**
* Creates a 'is null' conditional expression for a BIGINT value.
*
* @return a conditional expression
*/
public ConditionalExpression isNullBigInt() {
return new ConditionalExpression(BigIntColumn.ofNull(columnName), Operator.IS_NULL);
}

/**
* Creates a 'is null' conditional expression for a FLOAT value.
*
* @return a conditional expression
*/
public ConditionalExpression isNullFloat() {
return new ConditionalExpression(FloatColumn.ofNull(columnName), Operator.IS_NULL);
}

/**
* Creates a 'is null' conditional expression for a DOUBLE value.
*
* @return a conditional expression
*/
public ConditionalExpression isNullDouble() {
return new ConditionalExpression(DoubleColumn.ofNull(columnName), Operator.IS_NULL);
}

/**
* Creates a 'is null' conditional expression for a TEXT value.
*
* @return a conditional expression
*/
public ConditionalExpression isNullText() {
return new ConditionalExpression(TextColumn.ofNull(columnName), Operator.IS_NULL);
}

/**
* Creates a 'is null' conditional expression for a BLOB value.
*
* @return a conditional expression
*/
public ConditionalExpression isNullBlob() {
return new ConditionalExpression(BlobColumn.ofNull(columnName), Operator.IS_NULL);
}

/**
* Creates a 'is not null' conditional expression for a BOOLEAN value.
*
* @return a conditional expression
*/
public ConditionalExpression isNotNullBoolean() {
return new ConditionalExpression(BooleanColumn.ofNull(columnName), Operator.IS_NOT_NULL);
}

/**
* Creates a 'is not null' conditional expression for an INT value.
*
* @return a conditional expression
*/
public ConditionalExpression isNotNullInt() {
return new ConditionalExpression(IntColumn.ofNull(columnName), Operator.IS_NOT_NULL);
}

/**
* Creates a 'is not null' conditional expression for a BIGINT value.
*
* @return a conditional expression
*/
public ConditionalExpression isNotNullBigInt() {
return new ConditionalExpression(BigIntColumn.ofNull(columnName), Operator.IS_NOT_NULL);
}

/**
* Creates a 'is not null' conditional expression for a FLOAT value.
*
* @return a conditional expression
*/
public ConditionalExpression isNotNullFloat() {
return new ConditionalExpression(FloatColumn.ofNull(columnName), Operator.IS_NOT_NULL);
}

/**
* Creates a 'is not null' conditional expression for a DOUBLE value.
*
* @return a conditional expression
*/
public ConditionalExpression isNotNullDouble() {
return new ConditionalExpression(DoubleColumn.ofNull(columnName), Operator.IS_NOT_NULL);
}

/**
* Creates a 'is not null' conditional expression for a TEXT value.
*
* @return a conditional expression
*/
public ConditionalExpression isNotNullText() {
return new ConditionalExpression(TextColumn.ofNull(columnName), Operator.IS_NOT_NULL);
}

/**
* Creates a 'is not null' conditional expression for a BLOB value.
*
* @return a conditional expression
*/
public ConditionalExpression isNotNullBlob() {
return new ConditionalExpression(BlobColumn.ofNull(columnName), Operator.IS_NOT_NULL);
}
}

public static class PutIfBuilder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,5 +340,7 @@ public enum Operator {
GTE,
LT,
LTE,
IS_NULL,
IS_NOT_NULL
Comment on lines +343 to +344
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the new operators, IS_NULL and IS_NOT_NULL.

}
}
Loading