this.tableId = table.getTableId();
this.rowDef = table.rowDef();
this.fieldColumns = new int[columns.size()];
this.nullable = new boolean[fieldColumns.length];
for (int i = 0; i < fieldColumns.length; i++) {
Column column = columns.get(i);
fieldColumns[i] = column.getPosition();
nullable[i] = column.getNullable();
}
List<Column> defaultColumns = new ArrayList<>();
List<Column> functionColumns = new ArrayList<>();
for (Column column : table.getColumnsIncludingInternal()) {
if (columns.contains(column)) continue;
if (column.getIdentityGenerator() != null) {
functionColumns.add(column);
}
else if (column.getDefaultValue() != null) {
defaultColumns.add(column);
}
else if (column.getDefaultFunction() != null) {
functionColumns.add(column);
}
}
this.constColumns = new int[defaultColumns.size()];
for (int i = 0; i < constColumns.length; i++) {
constColumns[i] = defaultColumns.get(i).getPosition();
}
this.evalColumns = new int[functionColumns.size()];
for (int i = 0; i < evalColumns.length; i++) {
evalColumns[i] = functionColumns.get(i).getPosition();
}
this.vstring = new Value(typesTranslator.typeForString());
this.values = new Value[rowDef.getFieldCount()];
this.executionContexts = new TExecutionContext[values.length];
List<TInstance> inputs = Collections.singletonList(vstring.getType());
for (int fi = 0; fi < fieldColumns.length; fi++) {
int ci = fieldColumns[fi];
TInstance output = columns.get(fi).getType();
values[ci] = new Value(output);
// TODO: Only needed until every place gets type from
// ValueTarget, when there can just be one
// TExecutionContext wrapping the QueryContext.
executionContexts[ci] = new TExecutionContext(null,
inputs, output, queryContext,
ErrorHandlingMode.WARN,
ErrorHandlingMode.WARN,
ErrorHandlingMode.WARN);
}
for (int fi = 0; fi < constColumns.length; fi++) {
int ci = constColumns[fi];
Column column = defaultColumns.get(fi);
TInstance output = column.getType();
Value value = new Value(output);
TExecutionContext te = new TExecutionContext(null,
inputs, output, queryContext,
ErrorHandlingMode.WARN,
ErrorHandlingMode.WARN,
ErrorHandlingMode.WARN);
vstring.putString(column.getDefaultValue(), null);
value.getType().typeClass().fromObject(te, vstring, value);
values[ci] = value;
}
this.expressions = new TEvaluatableExpression[evalColumns.length];
TypesRegistryService registry = null;
if (evalColumns.length > 0) {
registry = queryContext.getServiceManager().getServiceByClass(TypesRegistryService.class);
}
for (int fi = 0; fi < evalColumns.length; fi++) {
int ci = evalColumns[fi];
Column column = functionColumns.get(fi);
TInstance columnType = column.getType();
String functionName;
List<TPreptimeValue> input;
List<TPreparedExpression> arguments;
if (column.getIdentityGenerator() != null) {
Sequence sequence = column.getIdentityGenerator();
TableName sequenceName = sequence.getSequenceName();
functionName = "NEXTVAL";
input = new ArrayList<>(2);
input.add(ValueSources.fromObject(sequenceName.getSchemaName(), typesTranslator.typeForString(sequenceName.getSchemaName())));
input.add(ValueSources.fromObject(sequenceName.getTableName(), typesTranslator.typeForString(sequenceName.getTableName())));
arguments = new ArrayList<>(input.size());
for (TPreptimeValue tpv : input) {
arguments.add(new TPreparedLiteral(tpv.type(), tpv.value()));
}
}
else {
functionName = column.getDefaultFunction();
assert (functionName != null) : column;
input = Collections.<TPreptimeValue>emptyList();
arguments = Collections.<TPreparedExpression>emptyList();
}
TValidatedScalar overload = registry.getScalarsResolver().get(functionName, input).getOverload();
TInstance functionType = overload.resultStrategy().fixed(column.getNullable());
TPreparedExpression expr = new TPreparedFunction(overload, functionType, arguments);
if (!functionType.equals(columnType)) {
TCast tcast = registry.getCastsResolver().cast(functionType.typeClass(), columnType.typeClass());
expr = new TCastExpression(expr, tcast, columnType);
}