[Feature](function) support generating const values from tvf numbers (#28051)

If specified, got a column of constant. otherwise an incremental series like it always be.

mysql> select * from numbers("number" = "5", "const_value" = "-123");
+--------+
| number |
+--------+
|   -123 |
|   -123 |
|   -123 |
|   -123 |
|   -123 |
+--------+
5 rows in set (0.11 sec)
This commit is contained in:
zclllyybb
2023-12-07 22:26:43 +08:00
committed by GitHub
parent 397a401241
commit 81a0f8c041
10 changed files with 136 additions and 60 deletions

View File

@ -65,17 +65,23 @@ public class Numbers extends TableValuedFunction {
public Statistics computeStats(List<Slot> slots) {
Preconditions.checkArgument(slots.size() == 1);
try {
NumbersTableValuedFunction catalogFunction = (NumbersTableValuedFunction) getCatalogFunction();
long rowNum = catalogFunction.getTotalNumbers();
NumbersTableValuedFunction numberTvf = (NumbersTableValuedFunction) getCatalogFunction();
long rowNum = numberTvf.getTotalNumbers();
Map<Expression, ColumnStatistic> columnToStatistics = Maps.newHashMap();
ColumnStatistic columnStat = new ColumnStatisticBuilder()
.setCount(rowNum).setNdv(rowNum).setAvgSizeByte(8).setNumNulls(0).setDataSize(8).setMinValue(0)
.setMaxValue(rowNum - 1)
.setMinExpr(new IntLiteral(0, Type.BIGINT))
.setMaxExpr(new IntLiteral(rowNum - 1, Type.BIGINT))
.build();
columnToStatistics.put(slots.get(0), columnStat);
ColumnStatisticBuilder statBuilder = new ColumnStatisticBuilder()
.setCount(rowNum).setAvgSizeByte(8).setNumNulls(0).setDataSize(8);
if (numberTvf.getUseConst()) { // a column of const value
long value = numberTvf.getConstValue();
statBuilder = statBuilder.setNdv(1).setMinValue(value).setMaxValue(value)
.setMinExpr(new IntLiteral(value, Type.BIGINT))
.setMaxExpr(new IntLiteral(value, Type.BIGINT));
} else { // a column of increasing value
statBuilder = statBuilder.setNdv(rowNum).setMinValue(0).setMaxValue(rowNum - 1)
.setMinExpr(new IntLiteral(0, Type.BIGINT))
.setMaxExpr(new IntLiteral(rowNum - 1, Type.BIGINT));
}
columnToStatistics.put(slots.get(0), statBuilder.build());
return new Statistics(rowNum, columnToStatistics);
} catch (Exception t) {
throw new NereidsException(t.getMessage(), t);

View File

@ -27,10 +27,8 @@ import org.apache.doris.thrift.TDataGenScanRange;
import org.apache.doris.thrift.TScanRange;
import org.apache.doris.thrift.TTVFNumbersScanRange;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.ArrayList;
import java.util.Collections;
@ -46,11 +44,15 @@ import java.util.Map;
public class NumbersTableValuedFunction extends DataGenTableValuedFunction {
public static final String NAME = "numbers";
public static final String NUMBER = "number";
public static final String CONST_VALUE = "const_value";
private static final ImmutableSet<String> PROPERTIES_SET = new ImmutableSet.Builder<String>()
.add(NUMBER)
.add(CONST_VALUE)
.build();
// The total numbers will be generated.
private long totalNumbers;
private boolean useConst = false;
private long constValue;
/**
* Constructor.
@ -58,24 +60,27 @@ public class NumbersTableValuedFunction extends DataGenTableValuedFunction {
* @throws AnalysisException exception
*/
public NumbersTableValuedFunction(Map<String, String> params) throws AnalysisException {
Map<String, String> validParams = Maps.newHashMap();
for (String key : params.keySet()) {
if (!PROPERTIES_SET.contains(key.toLowerCase())) {
throw new AnalysisException(key + " is invalid property");
}
validParams.put(key.toLowerCase(), params.get(key));
if (!params.containsKey(NUMBER)) {
throw new AnalysisException("number not set");
}
String numberStr = validParams.get(NUMBER);
if (!Strings.isNullOrEmpty(numberStr)) {
try {
totalNumbers = Long.parseLong(numberStr);
} catch (NumberFormatException e) {
throw new AnalysisException("can not parse `number` param to natural number");
for (String key : params.keySet()) {
if (PROPERTIES_SET.contains(key)) {
try {
switch (key) {
case NUMBER:
totalNumbers = Long.parseLong(params.get(key));
break;
case CONST_VALUE:
useConst = true;
constValue = Long.parseLong(params.get(key));
break;
default:
break;
}
} catch (NumberFormatException e) {
throw new AnalysisException("cannot parse param value " + params.get(key));
}
}
} else {
throw new AnalysisException(
"can not find `number` param, please specify `number`, like: numbers(\"number\" = \"10\")");
}
}
@ -83,6 +88,14 @@ public class NumbersTableValuedFunction extends DataGenTableValuedFunction {
return totalNumbers;
}
public boolean getUseConst() {
return useConst;
}
public long getConstValue() {
return constValue;
}
@Override
public TDataGenFunctionName getDataGenFunctionName() {
return TDataGenFunctionName.NUMBERS;
@ -116,8 +129,8 @@ public class NumbersTableValuedFunction extends DataGenTableValuedFunction {
List<TableValuedFunctionTask> res = Lists.newArrayList();
TScanRange scanRange = new TScanRange();
TDataGenScanRange dataGenScanRange = new TDataGenScanRange();
TTVFNumbersScanRange tvfNumbersScanRange = new TTVFNumbersScanRange();
tvfNumbersScanRange.setTotalNumbers(totalNumbers);
TTVFNumbersScanRange tvfNumbersScanRange = new TTVFNumbersScanRange().setTotalNumbers(totalNumbers)
.setUseConst(useConst).setConstValue(constValue);
dataGenScanRange.setNumbersParams(tvfNumbersScanRange);
scanRange.setDataGenScanRange(dataGenScanRange);
res.add(new TableValuedFunctionTask(backendList.get(0), scanRange));