
io.questdb.griffin.RecordToRowCopierUtils Maven / Gradle / Ivy
/*******************************************************************************
* ___ _ ____ ____
* / _ \ _ _ ___ ___| |_| _ \| __ )
* | | | | | | |/ _ \/ __| __| | | | _ \
* | |_| | |_| | __/\__ \ |_| |_| | |_) |
* \__\_\\__,_|\___||___/\__|____/|____/
*
* Copyright (c) 2014-2019 Appsicle
* Copyright (c) 2019-2023 QuestDB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
package io.questdb.griffin;
import io.questdb.cairo.ColumnFilter;
import io.questdb.cairo.ColumnType;
import io.questdb.cairo.ColumnTypes;
import io.questdb.cairo.TableWriter;
import io.questdb.cairo.sql.Record;
import io.questdb.cairo.sql.RecordMetadata;
import io.questdb.std.BytecodeAssembler;
import io.questdb.std.Misc;
import io.questdb.std.str.StringSink;
public class RecordToRowCopierUtils {
private RecordToRowCopierUtils() {
}
// Creates data type converter.
// INT and LONG NaN values are cast to their representation rather than Double or Float NaN.
public static RecordToRowCopier generateCopier(
BytecodeAssembler asm,
ColumnTypes from,
RecordMetadata to,
ColumnFilter toColumnFilter
) {
int timestampIndex = to.getTimestampIndex();
asm.init(RecordToRowCopier.class);
asm.setupPool();
int thisClassIndex = asm.poolClass(asm.poolUtf8("io/questdb/griffin/rowcopier"));
int interfaceClassIndex = asm.poolClass(RecordToRowCopier.class);
int rGetInt = asm.poolInterfaceMethod(Record.class, "getInt", "(I)I");
int rGetGeoInt = asm.poolInterfaceMethod(Record.class, "getGeoInt", "(I)I");
int rGetLong = asm.poolInterfaceMethod(Record.class, "getLong", "(I)J");
int rGetGeoLong = asm.poolInterfaceMethod(Record.class, "getGeoLong", "(I)J");
int rGetLong256 = asm.poolInterfaceMethod(Record.class, "getLong256A", "(I)Lio/questdb/std/Long256;");
int rGetLong128Lo = asm.poolInterfaceMethod(Record.class, "getLong128Lo", "(I)J");
int rGetLong128Hi = asm.poolInterfaceMethod(Record.class, "getLong128Hi", "(I)J");
int rGetDate = asm.poolInterfaceMethod(Record.class, "getDate", "(I)J");
int rGetTimestamp = asm.poolInterfaceMethod(Record.class, "getTimestamp", "(I)J");
//
int rGetByte = asm.poolInterfaceMethod(Record.class, "getByte", "(I)B");
int rGetGeoByte = asm.poolInterfaceMethod(Record.class, "getGeoByte", "(I)B");
int rGetShort = asm.poolInterfaceMethod(Record.class, "getShort", "(I)S");
int rGetGeoShort = asm.poolInterfaceMethod(Record.class, "getGeoShort", "(I)S");
int rGetChar = asm.poolInterfaceMethod(Record.class, "getChar", "(I)C");
int rGetBool = asm.poolInterfaceMethod(Record.class, "getBool", "(I)Z");
int rGetFloat = asm.poolInterfaceMethod(Record.class, "getFloat", "(I)F");
int rGetDouble = asm.poolInterfaceMethod(Record.class, "getDouble", "(I)D");
int rGetSym = asm.poolInterfaceMethod(Record.class, "getSym", "(I)Ljava/lang/CharSequence;");
int rGetStr = asm.poolInterfaceMethod(Record.class, "getStr", "(I)Ljava/lang/CharSequence;");
int rGetBin = asm.poolInterfaceMethod(Record.class, "getBin", "(I)Lio/questdb/std/BinarySequence;");
//
int wPutInt = asm.poolInterfaceMethod(TableWriter.Row.class, "putInt", "(II)V");
int wPutLong = asm.poolInterfaceMethod(TableWriter.Row.class, "putLong", "(IJ)V");
int wPutLong256 = asm.poolInterfaceMethod(TableWriter.Row.class, "putLong256", "(ILio/questdb/std/Long256;)V");
int wPutLong128 = asm.poolInterfaceMethod(TableWriter.Row.class, "putLong128", "(IJJ)V");
int wPutUuidStr = asm.poolInterfaceMethod(TableWriter.Row.class, "putUuid", "(ILjava/lang/CharSequence;)V");
int wPutDate = asm.poolInterfaceMethod(TableWriter.Row.class, "putDate", "(IJ)V");
int wPutTimestamp = asm.poolInterfaceMethod(TableWriter.Row.class, "putTimestamp", "(IJ)V");
//
int wPutByte = asm.poolInterfaceMethod(TableWriter.Row.class, "putByte", "(IB)V");
int wPutShort = asm.poolInterfaceMethod(TableWriter.Row.class, "putShort", "(IS)V");
int wPutBool = asm.poolInterfaceMethod(TableWriter.Row.class, "putBool", "(IZ)V");
int wPutFloat = asm.poolInterfaceMethod(TableWriter.Row.class, "putFloat", "(IF)V");
int wPutDouble = asm.poolInterfaceMethod(TableWriter.Row.class, "putDouble", "(ID)V");
int wPutSym = asm.poolInterfaceMethod(TableWriter.Row.class, "putSym", "(ILjava/lang/CharSequence;)V");
int wPutSymChar = asm.poolInterfaceMethod(TableWriter.Row.class, "putSym", "(IC)V");
int wPutStr = asm.poolInterfaceMethod(TableWriter.Row.class, "putStr", "(ILjava/lang/CharSequence;)V");
int wPutGeoStr = asm.poolInterfaceMethod(TableWriter.Row.class, "putGeoStr", "(ILjava/lang/CharSequence;)V");
int implicitCastCharAsByte = asm.poolMethod(SqlUtil.class, "implicitCastCharAsByte", "(CI)B");
int implicitCastCharAsGeoHash = asm.poolMethod(SqlUtil.class, "implicitCastCharAsGeoHash", "(CI)B");
int implicitCastStrAsFloat = asm.poolMethod(SqlUtil.class, "implicitCastStrAsFloat", "(Ljava/lang/CharSequence;)F");
int implicitCastStrAsDouble = asm.poolMethod(SqlUtil.class, "implicitCastStrAsDouble", "(Ljava/lang/CharSequence;)D");
int implicitCastStrAsByte = asm.poolMethod(SqlUtil.class, "implicitCastStrAsByte", "(Ljava/lang/CharSequence;)B");
int implicitCastStrAsShort = asm.poolMethod(SqlUtil.class, "implicitCastStrAsShort", "(Ljava/lang/CharSequence;)S");
int implicitCastStrAsChar = asm.poolMethod(SqlUtil.class, "implicitCastStrAsChar", "(Ljava/lang/CharSequence;)C");
int implicitCastStrAsInt = asm.poolMethod(SqlUtil.class, "implicitCastStrAsInt", "(Ljava/lang/CharSequence;)I");
int implicitCastStrAsLong = asm.poolMethod(SqlUtil.class, "implicitCastStrAsLong", "(Ljava/lang/CharSequence;)J");
int implicitCastStrAsDate = asm.poolMethod(SqlUtil.class, "implicitCastStrAsDate", "(Ljava/lang/CharSequence;)J");
int implicitCastStrAsTimestamp = asm.poolMethod(SqlUtil.class, "implicitCastStrAsTimestamp", "(Ljava/lang/CharSequence;)J");
int implicitCastDateAsTimestamp = asm.poolMethod(SqlUtil.class, "dateToTimestamp", "(J)J");
int implicitCastShortAsByte = asm.poolMethod(SqlUtil.class, "implicitCastShortAsByte", "(S)B");
int implicitCastIntAsByte = asm.poolMethod(SqlUtil.class, "implicitCastIntAsByte", "(I)B");
int implicitCastLongAsByte = asm.poolMethod(SqlUtil.class, "implicitCastLongAsByte", "(J)B");
int implicitCastFloatAsByte = asm.poolMethod(SqlUtil.class, "implicitCastFloatAsByte", "(F)B");
int implicitCastDoubleAsByte = asm.poolMethod(SqlUtil.class, "implicitCastDoubleAsByte", "(D)B");
int implicitCastIntAsShort = asm.poolMethod(SqlUtil.class, "implicitCastIntAsShort", "(I)S");
int implicitCastLongAsShort = asm.poolMethod(SqlUtil.class, "implicitCastLongAsShort", "(J)S");
int implicitCastFloatAsShort = asm.poolMethod(SqlUtil.class, "implicitCastFloatAsShort", "(F)S");
int implicitCastDoubleAsShort = asm.poolMethod(SqlUtil.class, "implicitCastDoubleAsShort", "(D)S");
int implicitCastLongAsInt = asm.poolMethod(SqlUtil.class, "implicitCastLongAsInt", "(J)I");
int implicitCastFloatAsInt = asm.poolMethod(SqlUtil.class, "implicitCastFloatAsInt", "(F)I");
int implicitCastDoubleAsInt = asm.poolMethod(SqlUtil.class, "implicitCastDoubleAsInt", "(D)I");
int implicitCastFloatAsLong = asm.poolMethod(SqlUtil.class, "implicitCastFloatAsLong", "(F)J");
int implicitCastDoubleAsLong = asm.poolMethod(SqlUtil.class, "implicitCastDoubleAsLong", "(D)J");
int implicitCastDoubleAsFloat = asm.poolMethod(SqlUtil.class, "implicitCastDoubleAsFloat", "(D)F");
int wPutStrChar = asm.poolInterfaceMethod(TableWriter.Row.class, "putStr", "(IC)V");
int wPutChar = asm.poolInterfaceMethod(TableWriter.Row.class, "putChar", "(IC)V");
int wPutBin = asm.poolInterfaceMethod(TableWriter.Row.class, "putBin", "(ILio/questdb/std/BinarySequence;)V");
int implicitCastGeoHashAsGeoHash = asm.poolMethod(SqlUtil.class, "implicitCastGeoHashAsGeoHash", "(JII)J");
int transferUuidToStrCol = asm.poolMethod(RecordToRowCopierUtils.class, "transferUuidToStrCol", "(Lio/questdb/cairo/TableWriter$Row;IJJ)V");
// in case of Geo Hashes column type can overflow short and asm.iconst() will not provide
// the correct value.
int n = toColumnFilter.getColumnCount();
// pool column type constants
int toColumnType_0 = asm.getPoolCount();
int fromColumnType_0 = toColumnType_0 + 1;
for (int i = 0; i < n; i++) {
asm.poolIntConst(
to.getColumnType(
toColumnFilter.getColumnIndexFactored(i))
);
asm.poolIntConst(from.getColumnType(i));
}
int copyNameIndex = asm.poolUtf8("copy");
int copySigIndex = asm.poolUtf8("(Lio/questdb/cairo/sql/Record;Lio/questdb/cairo/TableWriter$Row;)V");
asm.finishPool();
asm.defineClass(thisClassIndex);
asm.interfaceCount(1);
asm.putShort(interfaceClassIndex);
asm.fieldCount(0);
asm.methodCount(2);
asm.defineDefaultConstructor();
asm.startMethod(copyNameIndex, copySigIndex, 15, 5);
for (int i = 0; i < n; i++) {
final int toColumnIndex = toColumnFilter.getColumnIndexFactored(i);
// do not copy timestamp, it will be copied externally to this helper
if (toColumnIndex == timestampIndex) {
continue;
}
final int toColumnType = to.getColumnType(toColumnIndex);
final int fromColumnType = from.getColumnType(i);
final int toColumnTypeTag = ColumnType.tagOf(toColumnType);
final int toColumnWriterIndex = to.getWriterIndex(toColumnIndex);
asm.aload(2);
asm.iconst(toColumnWriterIndex);
asm.aload(1);
asm.iconst(i);
int fromColumnTypeTag = ColumnType.tagOf(fromColumnType);
if (fromColumnTypeTag == ColumnType.NULL) {
fromColumnTypeTag = toColumnTypeTag;
}
switch (fromColumnTypeTag) {
case ColumnType.INT:
asm.invokeInterface(rGetInt);
switch (toColumnTypeTag) {
case ColumnType.BYTE:
asm.invokeStatic(implicitCastIntAsByte);
asm.invokeInterface(wPutByte, 2);
break;
case ColumnType.SHORT:
asm.invokeStatic(implicitCastIntAsShort);
asm.invokeInterface(wPutShort, 2);
break;
case ColumnType.INT:
asm.invokeInterface(wPutInt, 2);
break;
case ColumnType.LONG:
asm.i2l();
asm.invokeInterface(wPutLong, 3);
break;
case ColumnType.DATE:
asm.i2l();
asm.invokeInterface(wPutDate, 3);
break;
case ColumnType.TIMESTAMP:
asm.i2l();
asm.invokeInterface(wPutTimestamp, 3);
break;
case ColumnType.FLOAT:
asm.i2f();
asm.invokeInterface(wPutFloat, 2);
break;
case ColumnType.DOUBLE:
asm.i2d();
asm.invokeInterface(wPutDouble, 3);
break;
default:
assert false;
break;
}
break;
case ColumnType.LONG:
asm.invokeInterface(rGetLong);
switch (toColumnTypeTag) {
case ColumnType.BYTE:
asm.invokeStatic(implicitCastLongAsByte);
asm.invokeInterface(wPutByte, 2);
break;
case ColumnType.SHORT:
asm.invokeStatic(implicitCastLongAsShort);
asm.invokeInterface(wPutShort, 2);
break;
case ColumnType.INT:
asm.invokeStatic(implicitCastLongAsInt);
asm.invokeInterface(wPutInt, 2);
break;
case ColumnType.LONG:
asm.invokeInterface(wPutLong, 3);
break;
case ColumnType.DATE:
asm.invokeInterface(wPutDate, 3);
break;
case ColumnType.TIMESTAMP:
asm.invokeInterface(wPutTimestamp, 3);
break;
case ColumnType.FLOAT:
asm.l2f();
asm.invokeInterface(wPutFloat, 2);
break;
case ColumnType.DOUBLE:
asm.l2d();
asm.invokeInterface(wPutDouble, 3);
break;
default:
assert false;
break;
}
break;
case ColumnType.DATE:
asm.invokeInterface(rGetDate);
switch (toColumnTypeTag) {
case ColumnType.BYTE:
asm.invokeStatic(implicitCastLongAsByte);
asm.invokeInterface(wPutByte, 2);
break;
case ColumnType.SHORT:
asm.invokeStatic(implicitCastLongAsShort);
asm.invokeInterface(wPutShort, 2);
break;
case ColumnType.INT:
asm.invokeStatic(implicitCastLongAsInt);
asm.invokeInterface(wPutInt, 2);
break;
case ColumnType.LONG:
asm.invokeInterface(wPutLong, 3);
break;
case ColumnType.DATE:
asm.invokeInterface(wPutDate, 3);
break;
case ColumnType.TIMESTAMP:
asm.invokeStatic(implicitCastDateAsTimestamp);
asm.invokeInterface(wPutTimestamp, 3);
break;
case ColumnType.FLOAT:
asm.l2f();
asm.invokeInterface(wPutFloat, 2);
break;
case ColumnType.DOUBLE:
asm.l2d();
asm.invokeInterface(wPutDouble, 3);
break;
default:
assert false;
break;
}
break;
case ColumnType.TIMESTAMP:
asm.invokeInterface(rGetTimestamp);
switch (toColumnTypeTag) {
case ColumnType.BYTE:
asm.invokeStatic(implicitCastLongAsByte);
asm.invokeInterface(wPutByte, 2);
break;
case ColumnType.SHORT:
asm.invokeStatic(implicitCastLongAsShort);
asm.invokeInterface(wPutShort, 2);
break;
case ColumnType.INT:
asm.invokeStatic(implicitCastLongAsInt);
asm.invokeInterface(wPutInt, 2);
break;
case ColumnType.LONG:
asm.invokeInterface(wPutLong, 3);
break;
case ColumnType.FLOAT:
asm.l2f();
asm.invokeInterface(wPutFloat, 2);
break;
case ColumnType.DOUBLE:
asm.l2d();
asm.invokeInterface(wPutDouble, 3);
break;
case ColumnType.DATE:
asm.invokeInterface(wPutDate, 3);
break;
case ColumnType.TIMESTAMP:
asm.invokeInterface(wPutTimestamp, 3);
break;
default:
assert false;
break;
}
break;
case ColumnType.BYTE:
asm.invokeInterface(rGetByte);
switch (toColumnTypeTag) {
case ColumnType.BYTE:
asm.invokeInterface(wPutByte, 2);
break;
case ColumnType.SHORT:
asm.i2s();
asm.invokeInterface(wPutShort, 2);
break;
case ColumnType.INT:
asm.invokeInterface(wPutInt, 2);
break;
case ColumnType.LONG:
asm.i2l();
asm.invokeInterface(wPutLong, 3);
break;
case ColumnType.DATE:
asm.i2l();
asm.invokeInterface(wPutDate, 3);
break;
case ColumnType.TIMESTAMP:
asm.i2l();
asm.invokeInterface(wPutTimestamp, 3);
break;
case ColumnType.FLOAT:
asm.i2f();
asm.invokeInterface(wPutFloat, 2);
break;
case ColumnType.DOUBLE:
asm.i2d();
asm.invokeInterface(wPutDouble, 3);
break;
default:
assert false;
break;
}
break;
case ColumnType.SHORT:
asm.invokeInterface(rGetShort);
switch (toColumnTypeTag) {
case ColumnType.BYTE:
asm.invokeStatic(implicitCastShortAsByte);
asm.invokeInterface(wPutByte, 2);
break;
case ColumnType.SHORT:
asm.invokeInterface(wPutShort, 2);
break;
case ColumnType.INT:
asm.invokeInterface(wPutInt, 2);
break;
case ColumnType.LONG:
asm.i2l();
asm.invokeInterface(wPutLong, 3);
break;
case ColumnType.DATE:
asm.i2l();
asm.invokeInterface(wPutDate, 3);
break;
case ColumnType.TIMESTAMP:
asm.i2l();
asm.invokeInterface(wPutTimestamp, 3);
break;
case ColumnType.FLOAT:
asm.i2f();
asm.invokeInterface(wPutFloat, 2);
break;
case ColumnType.DOUBLE:
asm.i2d();
asm.invokeInterface(wPutDouble, 3);
break;
default:
assert false;
break;
}
break;
case ColumnType.BOOLEAN:
assert toColumnType == ColumnType.BOOLEAN;
asm.invokeInterface(rGetBool);
asm.invokeInterface(wPutBool, 2);
break;
case ColumnType.FLOAT:
asm.invokeInterface(rGetFloat);
switch (toColumnTypeTag) {
case ColumnType.BYTE:
asm.invokeStatic(implicitCastFloatAsByte);
asm.invokeInterface(wPutByte, 2);
break;
case ColumnType.SHORT:
asm.invokeStatic(implicitCastFloatAsShort);
asm.invokeInterface(wPutShort, 2);
break;
case ColumnType.INT:
asm.invokeStatic(implicitCastFloatAsInt);
asm.invokeInterface(wPutInt, 2);
break;
case ColumnType.LONG:
asm.invokeStatic(implicitCastFloatAsLong);
asm.invokeInterface(wPutLong, 3);
break;
case ColumnType.DATE:
asm.invokeStatic(implicitCastFloatAsLong);
asm.invokeInterface(wPutDate, 3);
break;
case ColumnType.TIMESTAMP:
asm.invokeStatic(implicitCastFloatAsLong);
asm.invokeInterface(wPutTimestamp, 3);
break;
case ColumnType.FLOAT:
asm.invokeInterface(wPutFloat, 2);
break;
case ColumnType.DOUBLE:
asm.f2d();
asm.invokeInterface(wPutDouble, 3);
break;
default:
assert false;
break;
}
break;
case ColumnType.DOUBLE:
asm.invokeInterface(rGetDouble);
switch (toColumnTypeTag) {
case ColumnType.BYTE:
asm.invokeStatic(implicitCastDoubleAsByte);
asm.invokeInterface(wPutByte, 2);
break;
case ColumnType.SHORT:
asm.invokeStatic(implicitCastDoubleAsShort);
asm.invokeInterface(wPutShort, 2);
break;
case ColumnType.INT:
asm.invokeStatic(implicitCastDoubleAsInt);
asm.invokeInterface(wPutInt, 2);
break;
case ColumnType.LONG:
asm.invokeStatic(implicitCastDoubleAsLong);
asm.invokeInterface(wPutLong, 3);
break;
case ColumnType.DATE:
asm.invokeStatic(implicitCastDoubleAsLong);
asm.invokeInterface(wPutDate, 3);
break;
case ColumnType.TIMESTAMP:
asm.invokeStatic(implicitCastDoubleAsLong);
asm.invokeInterface(wPutTimestamp, 3);
break;
case ColumnType.FLOAT:
asm.invokeStatic(implicitCastDoubleAsFloat);
asm.invokeInterface(wPutFloat, 2);
break;
case ColumnType.DOUBLE:
asm.invokeInterface(wPutDouble, 3);
break;
default:
assert false;
break;
}
break;
case ColumnType.CHAR:
asm.invokeInterface(rGetChar);
switch (toColumnTypeTag) {
case ColumnType.BYTE:
asm.iconst(toColumnType);
asm.invokeStatic(implicitCastCharAsByte);
asm.invokeInterface(wPutByte, 2);
break;
case ColumnType.SHORT:
asm.iconst(toColumnType);
asm.invokeStatic(implicitCastCharAsByte);
asm.i2s();
asm.invokeInterface(wPutShort, 2);
break;
case ColumnType.CHAR:
asm.invokeInterface(wPutChar, 2);
break;
case ColumnType.INT:
asm.iconst(toColumnType);
asm.invokeStatic(implicitCastCharAsByte);
asm.invokeInterface(wPutInt, 2);
break;
case ColumnType.LONG:
asm.iconst(toColumnType);
asm.invokeStatic(implicitCastCharAsByte);
asm.i2l();
asm.invokeInterface(wPutLong, 3);
break;
case ColumnType.DATE:
asm.iconst(toColumnType);
asm.invokeStatic(implicitCastCharAsByte);
asm.i2l();
asm.invokeInterface(wPutDate, 3);
break;
case ColumnType.TIMESTAMP:
asm.iconst(toColumnType);
asm.invokeStatic(implicitCastCharAsByte);
asm.i2l();
asm.invokeInterface(wPutTimestamp, 3);
break;
case ColumnType.FLOAT:
asm.iconst(toColumnType);
asm.invokeStatic(implicitCastCharAsByte);
asm.i2f();
asm.invokeInterface(wPutFloat, 2);
break;
case ColumnType.DOUBLE:
asm.iconst(toColumnType);
asm.invokeStatic(implicitCastCharAsByte);
asm.i2d();
asm.invokeInterface(wPutDouble, 3);
break;
case ColumnType.STRING:
asm.invokeInterface(wPutStrChar, 2);
break;
case ColumnType.SYMBOL:
asm.invokeInterface(wPutSymChar, 2);
break;
case ColumnType.GEOBYTE:
asm.ldc(toColumnType_0 + i * 2);
asm.invokeStatic(implicitCastCharAsGeoHash);
asm.invokeInterface(wPutByte, 2);
break;
default:
assert false;
break;
}
break;
case ColumnType.SYMBOL:
asm.invokeInterface(rGetSym);
switch (toColumnTypeTag) {
case ColumnType.SYMBOL:
asm.invokeInterface(wPutSym, 2);
break;
case ColumnType.STRING:
asm.invokeInterface(wPutStr, 2);
break;
default:
assert false;
break;
}
break;
case ColumnType.STRING:
// This is generic code, and it acts on a record
// whereas Functions support string to primitive conversions, Record instances
// do not. This is because functions are aware of their return type but records
// would have to do expensive checks to decide which conversion would be required
asm.invokeInterface(rGetStr);
switch (toColumnTypeTag) {
case ColumnType.BYTE:
asm.invokeStatic(implicitCastStrAsByte);
asm.invokeInterface(wPutByte, 2);
break;
case ColumnType.SHORT:
asm.invokeStatic(implicitCastStrAsShort);
asm.invokeInterface(wPutShort, 2);
break;
case ColumnType.CHAR:
asm.invokeStatic(implicitCastStrAsChar);
asm.invokeInterface(wPutChar, 2);
break;
case ColumnType.INT:
asm.invokeStatic(implicitCastStrAsInt);
asm.invokeInterface(wPutInt, 2);
break;
case ColumnType.LONG:
asm.invokeStatic(implicitCastStrAsLong);
asm.invokeInterface(wPutLong, 3);
break;
case ColumnType.FLOAT:
asm.invokeStatic(implicitCastStrAsFloat);
asm.invokeInterface(wPutFloat, 2);
break;
case ColumnType.DOUBLE:
asm.invokeStatic(implicitCastStrAsDouble);
asm.invokeInterface(wPutDouble, 3);
break;
case ColumnType.SYMBOL:
asm.invokeInterface(wPutSym, 2);
break;
case ColumnType.DATE:
asm.invokeStatic(implicitCastStrAsDate);
asm.invokeInterface(wPutTimestamp, 3);
break;
case ColumnType.TIMESTAMP:
asm.invokeStatic(implicitCastStrAsTimestamp);
asm.invokeInterface(wPutTimestamp, 3);
break;
case ColumnType.GEOBYTE:
case ColumnType.GEOSHORT:
case ColumnType.GEOINT:
case ColumnType.GEOLONG:
asm.invokeInterface(wPutGeoStr, 2);
break;
case ColumnType.STRING:
asm.invokeInterface(wPutStr, 2);
break;
case ColumnType.UUID:
asm.invokeInterface(wPutUuidStr, 2);
break;
default:
assert false;
break;
}
break;
case ColumnType.BINARY:
assert toColumnTypeTag == ColumnType.BINARY;
asm.invokeInterface(rGetBin);
asm.invokeInterface(wPutBin, 2);
break;
case ColumnType.LONG256:
assert toColumnTypeTag == ColumnType.LONG256;
asm.invokeInterface(rGetLong256);
asm.invokeInterface(wPutLong256, 2);
break;
case ColumnType.GEOBYTE:
asm.invokeInterface(rGetGeoByte, 1);
if (fromColumnType != toColumnType && (fromColumnType != ColumnType.NULL && fromColumnType != ColumnType.GEOBYTE)) {
// truncate within the same storage type
asm.i2l();
asm.ldc(fromColumnType_0 + i * 2);
// toColumnType
asm.ldc(toColumnType_0 + i * 2);
asm.invokeStatic(implicitCastGeoHashAsGeoHash);
asm.l2i();
asm.i2b();
}
asm.invokeInterface(wPutByte, 2);
break;
case ColumnType.GEOSHORT:
asm.invokeInterface(rGetGeoShort, 1);
if (ColumnType.tagOf(toColumnType) == ColumnType.GEOBYTE) {
asm.i2l();
asm.ldc(fromColumnType_0 + i * 2);
asm.ldc(toColumnType_0 + i * 2);
asm.invokeStatic(implicitCastGeoHashAsGeoHash);
asm.l2i();
asm.i2b();
asm.invokeInterface(wPutByte, 2);
} else if (fromColumnType != toColumnType && fromColumnType != ColumnType.NULL && fromColumnType != ColumnType.GEOSHORT) {
asm.i2l();
asm.ldc(fromColumnType_0 + i * 2);
asm.ldc(toColumnType_0 + i * 2);
asm.invokeStatic(implicitCastGeoHashAsGeoHash);
asm.l2i();
asm.i2s();
asm.invokeInterface(wPutShort, 2);
} else {
asm.invokeInterface(wPutShort, 2);
}
break;
case ColumnType.GEOINT:
asm.invokeInterface(rGetGeoInt, 1);
switch (ColumnType.tagOf(toColumnType)) {
case ColumnType.GEOBYTE:
asm.i2l();
asm.ldc(fromColumnType_0 + i * 2);
asm.ldc(toColumnType_0 + i * 2);
asm.invokeStatic(implicitCastGeoHashAsGeoHash);
asm.l2i();
asm.i2b();
asm.invokeInterface(wPutByte, 2);
break;
case ColumnType.GEOSHORT:
asm.i2l();
asm.ldc(fromColumnType_0 + i * 2);
asm.ldc(toColumnType_0 + i * 2);
asm.invokeStatic(implicitCastGeoHashAsGeoHash);
asm.l2i();
asm.i2s();
asm.invokeInterface(wPutShort, 2);
break;
case ColumnType.GEOINT:
if (fromColumnType != toColumnType && fromColumnType != ColumnType.NULL && fromColumnType != ColumnType.GEOINT) {
asm.i2l();
asm.ldc(fromColumnType_0 + i * 2);
asm.ldc(toColumnType_0 + i * 2);
asm.invokeStatic(implicitCastGeoHashAsGeoHash);
asm.l2i();
}
asm.invokeInterface(wPutInt, 2);
break;
default:
assert false;
break;
}
break;
case ColumnType.GEOLONG:
asm.invokeInterface(rGetGeoLong, 1);
switch (ColumnType.tagOf(toColumnType)) {
case ColumnType.GEOBYTE:
asm.ldc(fromColumnType_0 + i * 2);
asm.ldc(toColumnType_0 + i * 2);
asm.invokeStatic(implicitCastGeoHashAsGeoHash);
asm.l2i();
asm.i2b();
asm.invokeInterface(wPutByte, 2);
break;
case ColumnType.GEOSHORT:
asm.ldc(fromColumnType_0 + i * 2);
asm.ldc(toColumnType_0 + i * 2);
asm.invokeStatic(implicitCastGeoHashAsGeoHash);
asm.l2i();
asm.i2s();
asm.invokeInterface(wPutShort, 2);
break;
case ColumnType.GEOINT:
asm.ldc(fromColumnType_0 + i * 2);
asm.ldc(toColumnType_0 + i * 2);
asm.invokeStatic(implicitCastGeoHashAsGeoHash);
asm.l2i();
asm.invokeInterface(wPutInt, 2);
break;
case ColumnType.GEOLONG:
if (fromColumnType != toColumnType && fromColumnType != ColumnType.NULL && fromColumnType != ColumnType.GEOLONG) {
asm.ldc(fromColumnType_0 + i * 2);
asm.ldc(toColumnType_0 + i * 2);
asm.invokeStatic(implicitCastGeoHashAsGeoHash);
}
asm.invokeInterface(wPutLong, 3);
break;
default:
assert false;
break;
}
break;
case ColumnType.LONG128:
// fall through
case ColumnType.UUID:
switch (ColumnType.tagOf(toColumnType)) {
case ColumnType.LONG128:
// fall through
case ColumnType.UUID:
// Stack: [RowWriter, Record, columnIndex]
asm.invokeInterface(rGetLong128Lo, 1);
// Stack: [RowWriter, lo]
asm.aload(1); // Push record to the stack.
// Stack: [RowWriter, lo, Record]
asm.iconst(i); // Push column index to a stack
// Stack: [RowWriter, lo, Record, columnIndex]
asm.invokeInterface(rGetLong128Hi, 1);
// Stack: [RowWriter, lo, hi]
asm.invokeInterface(wPutLong128, 5);
// invokeInterface consumes the entire stack. Including the RowWriter as invoke interface receives "this" as the first argument
// The stack is now empty, and we are done with this column
break;
case ColumnType.STRING:
assert fromColumnType == ColumnType.UUID;
// this logic is very similar to the one for ColumnType.UUID above
// There is one major difference: `SqlUtil.implicitCastUuidAsStr()` returns `false` to indicate
// that the UUID value represents null. In this case we won't call the writer and let null value
// to be written by TableWriter/WalWriter NullSetters. However, generating branches via asm is
// complicated as JVM requires jump targets to have stack maps, etc. This would complicate things
// so we rely on an auxiliary method `transferUuidToStrCol()` to do branching job and javac generates
// the stack maps.
// Stack: [RowWriter, Record, columnIndex]
asm.invokeInterface(rGetLong128Lo, 1);
// Stack: [RowWriter, lo]
asm.aload(1); // Push record to the stack.
// Stack: [RowWriter, lo, Record]
asm.iconst(i); // Push column index to a stack
// Stack: [RowWriter, lo, Record, columnIndex]
asm.invokeInterface(rGetLong128Hi, 1);
// Stack: [RowWriter, lo, hi]
asm.invokeStatic(transferUuidToStrCol);
break;
default:
assert false;
break;
}
break;
default:
// we don't need to do anything for null as null is already written by TableWriter/WalWriter NullSetters
// every non-null-type is an error
assert fromColumnType == ColumnType.NULL;
}
}
asm.return_();
asm.endMethodCode();
// exceptions
asm.putShort(0);
// we have do not have to add a stack map table because there are no branches
// attributes: 0 (void, no branches -> no stack verification)
asm.putShort(0);
asm.endMethod();
// class attribute count
asm.putShort(0);
return asm.newInstance();
}
// Called from dynamically generated bytecode
public static void transferUuidToStrCol(TableWriter.Row row, int col, long lo, long hi) {
StringSink threadLocalBuilder = Misc.getThreadLocalBuilder();
if (SqlUtil.implicitCastUuidAsStr(lo, hi, threadLocalBuilder)) {
row.putStr(col, threadLocalBuilder);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy