• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

apache / iotdb / #9919

25 Aug 2023 07:08AM UTC coverage: 47.802% (+0.007%) from 47.795%
#9919

push

travis_ci

web-flow
Remove some useless configs (#10950)

80023 of 167404 relevant lines covered (47.8%)

0.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

59.05
/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one
3
 * or more contributor license agreements.  See the NOTICE file
4
 * distributed with this work for additional information
5
 * regarding copyright ownership.  The ASF licenses this file
6
 * to you under the Apache License, Version 2.0 (the
7
 * "License"); you may not use this file except in compliance
8
 * with the License.  You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19

20
package org.apache.iotdb.db.utils;
21

22
import org.apache.iotdb.commons.path.MeasurementPath;
23
import org.apache.iotdb.db.conf.IoTDBDescriptor;
24
import org.apache.iotdb.db.exception.sql.SemanticException;
25
import org.apache.iotdb.db.queryengine.plan.analyze.ExpressionUtils;
26
import org.apache.iotdb.db.queryengine.plan.expression.Expression;
27
import org.apache.iotdb.db.queryengine.plan.expression.binary.CompareBinaryExpression;
28
import org.apache.iotdb.db.queryengine.plan.expression.leaf.ConstantOperand;
29
import org.apache.iotdb.db.queryengine.plan.expression.leaf.TimeSeriesOperand;
30
import org.apache.iotdb.db.queryengine.plan.expression.multi.FunctionExpression;
31
import org.apache.iotdb.db.queryengine.plan.expression.multi.builtin.BuiltInScalarFunctionHelper;
32
import org.apache.iotdb.db.queryengine.plan.expression.multi.builtin.BuiltInScalarFunctionHelperFactory;
33
import org.apache.iotdb.db.utils.constant.SqlConstant;
34
import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
35
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
36

37
import org.apache.commons.lang3.StringUtils;
38

39
import java.util.Collections;
40
import java.util.List;
41

42
public class TypeInferenceUtils {
43

44
  private static final TSDataType booleanStringInferType =
45
      IoTDBDescriptor.getInstance().getConfig().getBooleanStringInferType();
1✔
46

47
  private static final TSDataType integerStringInferType =
48
      IoTDBDescriptor.getInstance().getConfig().getIntegerStringInferType();
1✔
49

50
  private static final TSDataType longStringInferType =
51
      IoTDBDescriptor.getInstance().getConfig().getLongStringInferType();
1✔
52

53
  private static final TSDataType floatingStringInferType =
54
      IoTDBDescriptor.getInstance().getConfig().getFloatingStringInferType();
1✔
55

56
  private static final TSDataType nanStringInferType =
1✔
57
      IoTDBDescriptor.getInstance().getConfig().getNanStringInferType();
1✔
58

59
  private TypeInferenceUtils() {}
60

61
  static boolean isNumber(String s) {
62
    if (s == null || s.equals("NaN")) {
1✔
63
      return false;
×
64
    }
65
    try {
66
      Double.parseDouble(s);
1✔
67
    } catch (NumberFormatException e) {
1✔
68
      return false;
1✔
69
    }
1✔
70
    return true;
1✔
71
  }
72

73
  private static boolean isBoolean(String s) {
74
    return s.equalsIgnoreCase(SqlConstant.BOOLEAN_TRUE)
1✔
75
        || s.equalsIgnoreCase(SqlConstant.BOOLEAN_FALSE);
1✔
76
  }
77

78
  private static boolean isConvertFloatPrecisionLack(String s) {
79
    try {
80
      return Long.parseLong(s) > (1 << 24);
1✔
81
    } catch (NumberFormatException e) {
1✔
82
      return true;
1✔
83
    }
84
  }
85

86
  /** Get predicted DataType of the given value */
87
  public static TSDataType getPredictedDataType(Object value, boolean inferType) {
88

89
    if (inferType) {
1✔
90
      String strValue = value.toString();
1✔
91
      if (isBoolean(strValue)) {
1✔
92
        return booleanStringInferType;
1✔
93
      } else if (isNumber(strValue)) {
1✔
94
        if (!strValue.contains(TsFileConstant.PATH_SEPARATOR)) {
1✔
95
          if (isConvertFloatPrecisionLack(StringUtils.trim(strValue))) {
1✔
96
            return longStringInferType;
1✔
97
          }
98
          return integerStringInferType;
1✔
99
        } else {
100
          return floatingStringInferType;
1✔
101
        }
102
      } else if ("null".equals(strValue) || "NULL".equals(strValue)) {
1✔
103
        return null;
×
104
        // "NaN" is returned if the NaN Literal is given in Parser
105
      } else if ("NaN".equals(strValue)) {
1✔
106
        return nanStringInferType;
×
107
      } else {
108
        return TSDataType.TEXT;
1✔
109
      }
110
    } else if (value instanceof Boolean) {
1✔
111
      return TSDataType.BOOLEAN;
1✔
112
    } else if (value instanceof Integer) {
1✔
113
      return TSDataType.INT32;
1✔
114
    } else if (value instanceof Long) {
1✔
115
      return TSDataType.INT64;
×
116
    } else if (value instanceof Float) {
1✔
117
      return TSDataType.FLOAT;
1✔
118
    } else if (value instanceof Double) {
1✔
119
      return TSDataType.DOUBLE;
1✔
120
    }
121

122
    return TSDataType.TEXT;
1✔
123
  }
124

125
  public static TSDataType getAggrDataType(String aggrFuncName, TSDataType dataType) {
126
    if (aggrFuncName == null) {
1✔
127
      throw new IllegalArgumentException("AggregateFunction Name must not be null");
×
128
    }
129
    verifyIsAggregationDataTypeMatched(aggrFuncName, dataType);
1✔
130

131
    switch (aggrFuncName.toLowerCase()) {
1✔
132
      case SqlConstant.MIN_TIME:
133
      case SqlConstant.MAX_TIME:
134
      case SqlConstant.COUNT:
135
      case SqlConstant.COUNT_TIME:
136
      case SqlConstant.COUNT_IF:
137
      case SqlConstant.TIME_DURATION:
138
        return TSDataType.INT64;
1✔
139
      case SqlConstant.MIN_VALUE:
140
      case SqlConstant.LAST_VALUE:
141
      case SqlConstant.FIRST_VALUE:
142
      case SqlConstant.MAX_VALUE:
143
      case SqlConstant.EXTREME:
144
      case SqlConstant.MODE:
145
        return dataType;
1✔
146
      case SqlConstant.AVG:
147
      case SqlConstant.SUM:
148
        return TSDataType.DOUBLE;
1✔
149
      default:
150
        throw new IllegalArgumentException("Invalid Aggregation function: " + aggrFuncName);
×
151
    }
152
  }
153

154
  private static void verifyIsAggregationDataTypeMatched(String aggrFuncName, TSDataType dataType) {
155
    // input is NullOperand, needn't check
156
    if (dataType == null) {
1✔
157
      return;
×
158
    }
159
    switch (aggrFuncName.toLowerCase()) {
1✔
160
      case SqlConstant.AVG:
161
      case SqlConstant.SUM:
162
      case SqlConstant.EXTREME:
163
      case SqlConstant.MIN_VALUE:
164
      case SqlConstant.MAX_VALUE:
165
        if (dataType.isNumeric()) {
1✔
166
          return;
1✔
167
        }
168
        throw new SemanticException(
×
169
            "Aggregate functions [AVG, SUM, EXTREME, MIN_VALUE, MAX_VALUE] only support numeric data types [INT32, INT64, FLOAT, DOUBLE]");
170
      case SqlConstant.COUNT:
171
      case SqlConstant.COUNT_TIME:
172
      case SqlConstant.MIN_TIME:
173
      case SqlConstant.MAX_TIME:
174
      case SqlConstant.FIRST_VALUE:
175
      case SqlConstant.LAST_VALUE:
176
      case SqlConstant.TIME_DURATION:
177
      case SqlConstant.MODE:
178
        return;
1✔
179
      case SqlConstant.COUNT_IF:
180
        if (dataType != TSDataType.BOOLEAN) {
×
181
          throw new SemanticException(
×
182
              String.format(
×
183
                  "Input series of Aggregation function [%s] only supports data type [BOOLEAN]",
184
                  aggrFuncName));
185
        }
186
        return;
×
187
      default:
188
        throw new IllegalArgumentException("Invalid Aggregation function: " + aggrFuncName);
×
189
    }
190
  }
191

192
  /**
193
   * Bind Type for non-series input Expressions of AggregationFunction and check Semantic
194
   *
195
   * <p>.e.g COUNT_IF(s1>1, keep>2, 'ignoreNull'='false'), we bind type {@link TSDataType#INT64} for
196
   * 'keep'
197
   */
198
  public static void bindTypeForAggregationNonSeriesInputExpressions(
199
      String functionName,
200
      List<Expression> inputExpressions,
201
      List<List<Expression>> outputExpressionLists) {
202
    switch (functionName.toLowerCase()) {
1✔
203
      case SqlConstant.AVG:
204
      case SqlConstant.SUM:
205
      case SqlConstant.EXTREME:
206
      case SqlConstant.MIN_VALUE:
207
      case SqlConstant.MAX_VALUE:
208
      case SqlConstant.COUNT:
209
      case SqlConstant.COUNT_TIME:
210
      case SqlConstant.MIN_TIME:
211
      case SqlConstant.MAX_TIME:
212
      case SqlConstant.FIRST_VALUE:
213
      case SqlConstant.LAST_VALUE:
214
      case SqlConstant.TIME_DURATION:
215
      case SqlConstant.MODE:
216
        return;
1✔
217
      case SqlConstant.COUNT_IF:
218
        Expression keepExpression = inputExpressions.get(1);
×
219
        if (keepExpression instanceof ConstantOperand) {
×
220
          outputExpressionLists.add(Collections.singletonList(keepExpression));
×
221
          return;
×
222
        } else if (keepExpression instanceof CompareBinaryExpression) {
×
223
          Expression leftExpression =
×
224
              ((CompareBinaryExpression) keepExpression).getLeftExpression();
×
225
          Expression rightExpression =
×
226
              ((CompareBinaryExpression) keepExpression).getRightExpression();
×
227
          if (leftExpression instanceof TimeSeriesOperand
×
228
              && leftExpression.getExpressionString().equalsIgnoreCase("keep")
×
229
              && rightExpression.isConstantOperand()) {
×
230
            outputExpressionLists.add(
×
231
                Collections.singletonList(
×
232
                    ExpressionUtils.reconstructBinaryExpression(
×
233
                        keepExpression,
234
                        new TimeSeriesOperand(
235
                            new MeasurementPath(
236
                                ((TimeSeriesOperand) leftExpression).getPath(), TSDataType.INT64)),
×
237
                        rightExpression)));
238
            return;
×
239
          } else {
240
            throw new SemanticException(
×
241
                String.format(
×
242
                    "Please check input keep condition of Aggregation function [%s]",
243
                    functionName));
244
          }
245
        } else {
246
          throw new SemanticException(
×
247
              String.format(
×
248
                  "Keep condition of Aggregation function [%s] need to be constant or compare expression constructed by keep and a long number",
249
                  functionName));
250
        }
251
      default:
252
        throw new IllegalArgumentException("Invalid Aggregation function: " + functionName);
×
253
    }
254
  }
255

256
  public static TSDataType getBuiltInScalarFunctionDataType(
257
      FunctionExpression functionExpression, TSDataType dataType) {
258
    String functionName = functionExpression.getFunctionName();
1✔
259
    if (functionName == null) {
1✔
260
      throw new IllegalArgumentException("ScalarFunction Name must not be null.");
×
261
    }
262
    BuiltInScalarFunctionHelper helper =
1✔
263
        BuiltInScalarFunctionHelperFactory.createHelper(functionName);
1✔
264
    // check input data type first if it is not a NullOperand
265
    if (dataType != null) {
1✔
266
      helper.checkBuiltInScalarFunctionInputDataType(dataType);
1✔
267
    }
268
    return helper.getBuiltInScalarFunctionReturnType(functionExpression);
1✔
269
  }
270

271
  public static boolean canAutoCast(TSDataType fromType, TSDataType toType) {
272
    if (fromType.equals(toType)) {
1✔
273
      return true;
1✔
274
    }
275

276
    switch (fromType) {
×
277
      case INT32:
278
        switch (toType) {
×
279
          case INT64:
280
          case FLOAT:
281
          case DOUBLE:
282
            return true;
×
283
          default:
284
            return false;
×
285
        }
286
      case INT64:
287
      case FLOAT:
288
        return toType.equals(TSDataType.DOUBLE);
×
289
      case DOUBLE:
290
      case BOOLEAN:
291
      case TEXT:
292
        return false;
×
293
      default:
294
        throw new IllegalArgumentException("Unknown data type: " + fromType);
×
295
    }
296
  }
297
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc