Add unix time conversion functions

Patch by Kanthi Subramanian; reviewed by Benjamin Lerer and Brandon
Williams for CASSANDRA-17029
This commit is contained in:
Kanthi Subramanian 2021-10-17 17:18:58 -04:00 committed by Benjamin Lerer
parent b29e1037e4
commit 8ddcd43b0c
6 changed files with 122 additions and 3 deletions

View File

@ -1,4 +1,5 @@
4.1
* Add unix time conversion functions (CASSANDRA-17029)
* JVMStabilityInspector.forceHeapSpaceOomMaybe should handle all non-heap OOMs rather than only supporting direct only (CASSANDRA-17128)
* Forbid other Future implementations with checkstyle (CASSANDRA-17055)
* commit log was switched from non-daemon to daemon threads, which causes the JVM to exit in some case as no non-daemon threads are active (CASSANDRA-17085)

View File

@ -38,6 +38,8 @@ using the provided 'sstableupgrade' tool.
New features
------------
- New native functions to convert unix time values into C* native types: toDate(bigint), toTimestamp(bigint),
mintimeuuid(bigint) and maxtimeuuid(bigint)
- Support for multiple permission in a single GRANT/REVOKE/LIST statement has been added. It allows to
grant/revoke/list multiple permissions using a single statement by providing a list of comma-separated
permissions.

View File

@ -42,14 +42,18 @@ public abstract class TimeFcts
now("currentdate", SimpleDateType.instance),
now("currenttime", TimeType.instance),
minTimeuuidFct,
minTimeuuidFct(LongType.instance),
maxTimeuuidFct,
maxTimeuuidFct(LongType.instance),
dateOfFct,
unixTimestampOfFct,
toDate(TimeUUIDType.instance),
toTimestamp(TimeUUIDType.instance),
toTimestamp(LongType.instance),
toUnixTimestamp(TimeUUIDType.instance),
toUnixTimestamp(TimestampType.instance),
toDate(TimestampType.instance),
toDate(LongType.instance),
toUnixTimestamp(SimpleDateType.instance),
toTimestamp(SimpleDateType.instance));
}
@ -64,7 +68,7 @@ public abstract class TimeFcts
return type.now();
}
};
};
}
public static final Function minTimeuuidFct = new NativeScalarFunction("mintimeuuid", TimeUUIDType.instance, TimestampType.instance)
{
@ -78,6 +82,21 @@ public abstract class TimeFcts
}
};
public static final NativeScalarFunction minTimeuuidFct(final LongType type)
{
return new NativeScalarFunction("mintimeuuid", TimeUUIDType.instance, type)
{
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
{
ByteBuffer bb = parameters.get(0);
if (bb == null)
return null;
return UUIDGen.toByteBuffer(UUIDGen.minTimeUUID(LongType.instance.toLong(bb)));
}
};
}
public static final Function maxTimeuuidFct = new NativeScalarFunction("maxtimeuuid", TimeUUIDType.instance, TimestampType.instance)
{
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
@ -90,6 +109,21 @@ public abstract class TimeFcts
}
};
public static NativeScalarFunction maxTimeuuidFct(final LongType type)
{
return new NativeScalarFunction("maxtimeuuid", TimeUUIDType.instance, type)
{
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
{
ByteBuffer bb = parameters.get(0);
if (bb == null)
return null;
return UUIDGen.toByteBuffer(UUIDGen.maxTimeUUID(LongType.instance.toLong(bb)));
}
};
}
/**
* Function that convert a value of <code>TIMEUUID</code> into a value of type <code>TIMESTAMP</code>.
* @deprecated Replaced by the {@link #timeUuidToTimestamp} function
@ -162,6 +196,28 @@ public abstract class TimeFcts
};
}
/**
* Creates a function that convert a value of CQL(bigint) into a <code>DATE</code>.
* @param type the temporal type
* @return a function that convert CQL(bigint) into a <code>DATE</code>.
*/
public static NativeScalarFunction toDate(final LongType type)
{
return new NativeScalarFunction("todate", SimpleDateType.instance, type)
{
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
{
ByteBuffer bb = parameters.get(0);
if (bb == null || !bb.hasRemaining())
return null;
long millis = LongType.instance.toLong(bb);
return SimpleDateType.instance.fromTimeInMillis(millis);
}
};
}
/**
* Creates a function that convert a value of the specified type into a <code>TIMESTAMP</code>.
* @param type the temporal type
@ -183,6 +239,27 @@ public abstract class TimeFcts
};
}
/**
* Creates a function that convert a value of the specified type into a <code>TIMESTAMP</code>.
* @param type the temporal type
* @return a function that convert a value of the specified type into a <code>TIMESTAMP</code>.
*/
public static NativeScalarFunction toTimestamp(final LongType type)
{
return new NativeScalarFunction("totimestamp", TimestampType.instance, type)
{
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
{
ByteBuffer bb = parameters.get(0);
if (bb == null || !bb.hasRemaining())
return null;
long millis = LongType.instance.toLong(bb);
return TimestampType.instance.fromTimeInMillis(millis);
}
};
}
/**
* Creates a function that convert a value of the specified type into an UNIX timestamp.
* @param type the temporal type

View File

@ -139,7 +139,7 @@ public class LongType extends NumberType<Long>
}
@Override
protected long toLong(ByteBuffer value)
public long toLong(ByteBuffer value)
{
return ByteBufferUtil.toLong(value);
}

View File

@ -26,6 +26,7 @@ import java.util.List;
import org.junit.Test;
import org.apache.cassandra.db.marshal.IntegerType;
import org.apache.cassandra.db.marshal.LongType;
import org.apache.cassandra.db.marshal.SimpleDateType;
import org.apache.cassandra.db.marshal.TimeUUIDType;
@ -59,6 +60,15 @@ public class TimeFctsTest
assertEquals(UUIDGen.minTimeUUID(timeInMillis), TimeUUIDType.instance.compose(output));
}
@Test
public void testMinTimeUuidFromBigInt()
{
long timeInMillis = DATE_TIME.toInstant().toEpochMilli();
ByteBuffer input = LongType.instance.decompose(timeInMillis);
ByteBuffer output = executeFunction(TimeFcts.minTimeuuidFct(LongType.instance), input);
assertEquals(UUIDGen.minTimeUUID(timeInMillis), TimeUUIDType.instance.compose(output));
}
@Test
public void testMaxTimeUuid()
{
@ -68,6 +78,15 @@ public class TimeFctsTest
assertEquals(UUIDGen.maxTimeUUID(timeInMillis), TimeUUIDType.instance.compose(output));
}
@Test
public void testMaxTimeUuidFromBigInt()
{
long timeInMillis = DATE_TIME.toInstant().toEpochMilli();
ByteBuffer input = LongType.instance.decompose(timeInMillis);
ByteBuffer output = executeFunction(TimeFcts.maxTimeuuidFct(LongType.instance), input);
assertEquals(UUIDGen.maxTimeUUID(timeInMillis), TimeUUIDType.instance.compose(output));
}
@Test
public void testDateOf()
{
@ -141,6 +160,16 @@ public class TimeFctsTest
assertEquals(DATE.toInstant().toEpochMilli(), SimpleDateType.instance.toTimeInMillis(output));
}
@Test
public void testBigIntegerToDate()
{
long millis = DATE.toInstant().toEpochMilli();
ByteBuffer input = LongType.instance.decompose(millis);
ByteBuffer output = executeFunction(toDate(LongType.instance), input);
assertEquals(DATE.toInstant().toEpochMilli(), SimpleDateType.instance.toTimeInMillis(output));
}
@Test
public void testTimestampToDateWithEmptyInput()
{
@ -156,6 +185,16 @@ public class TimeFctsTest
assertEquals(DATE_TIME.toInstant().toEpochMilli(), LongType.instance.compose(output).longValue());
}
@Test
public void testBigIntegerToTimestamp()
{
long millis = DATE_TIME.toInstant().toEpochMilli();
ByteBuffer input = LongType.instance.decompose(millis);
ByteBuffer output = executeFunction(toTimestamp(LongType.instance), input);
assertEquals(DATE_TIME.toInstant().toEpochMilli(), LongType.instance.compose(output).longValue());
}
@Test
public void testTimestampToUnixTimestampWithEmptyInput()
{

View File

@ -64,7 +64,7 @@ public class TimeuuidTest extends CQLTester
row(new Date(timestamp), timestamp));
}
assertEmpty(execute("SELECT t FROM %s WHERE k = 0 AND t > maxTimeuuid(1234567) AND t < minTimeuuid('2012-11-07 18:18:22-0800')"));
assertEmpty(execute("SELECT t FROM %s WHERE k = 0 AND t > maxTimeuuid(1564830182000) AND t < minTimeuuid('2012-11-07 18:18:22-0800')"));
}
/**