Commit 1176f0de268d70ba76c008eaaadf8ef93f2db6c2

Authored by Igor Kulikov
2 parents 40a99403 c83c2321

Merge branch 'master' of github.com:thingsboard/thingsboard

... ... @@ -43,7 +43,7 @@ BEGIN
43 43 into max_customer_ttl;
44 44 max_ttl := GREATEST(system_ttl, max_customer_ttl, max_tenant_ttl);
45 45 if max_ttl IS NOT NULL AND max_ttl > 0 THEN
46   - date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - (max_ttl / 1000));
  46 + date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - max_ttl);
47 47 partition_by_max_ttl_date := get_partition_by_max_ttl_date(partition_type, date);
48 48 RAISE NOTICE 'Partition by max ttl: %', partition_by_max_ttl_date;
49 49 IF partition_by_max_ttl_date IS NOT NULL THEN
... ...
... ... @@ -193,6 +193,9 @@ public class ThingsboardInstallService {
193 193 databaseEntitiesUpgradeService.upgradeDatabase("3.2.1");
194 194 case "3.2.2":
195 195 log.info("Upgrading ThingsBoard from version 3.2.2 to 3.3.0 ...");
  196 + if (databaseTsUpgradeService != null) {
  197 + databaseTsUpgradeService.upgradeDatabase("3.2.2");
  198 + }
196 199 databaseEntitiesUpgradeService.upgradeDatabase("3.2.2");
197 200
198 201 dataUpdateService.updateData("3.2.2");
... ...
... ... @@ -209,6 +209,12 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe
209 209 executeQuery(conn, "DROP FUNCTION IF EXISTS delete_customer_records_from_ts_kv(character varying, character varying, bigint);");
210 210 }
211 211 break;
  212 + case "3.2.2":
  213 + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
  214 + log.info("Load Drop Partitions functions ...");
  215 + loadSql(conn, LOAD_DROP_PARTITIONS_FUNCTIONS_SQL, "2.4.3");
  216 + }
  217 + break;
212 218 default:
213 219 throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion);
214 220 }
... ...
... ... @@ -120,13 +120,17 @@
120 120 <groupId>org.apache.curator</groupId>
121 121 <artifactId>curator-recipes</artifactId>
122 122 </dependency>
123   -
124 123 <dependency>
125 124 <groupId>junit</groupId>
126 125 <artifactId>junit</artifactId>
127 126 <scope>test</scope>
128 127 </dependency>
129 128 <dependency>
  129 + <groupId>org.hamcrest</groupId>
  130 + <artifactId>hamcrest</artifactId>
  131 + <scope>test</scope>
  132 + </dependency>
  133 + <dependency>
130 134 <groupId>org.mockito</groupId>
131 135 <artifactId>mockito-core</artifactId>
132 136 <scope>test</scope>
... ...
... ... @@ -41,6 +41,7 @@ import org.thingsboard.server.common.transport.TransportServiceCallback;
41 41 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
42 42 import org.thingsboard.server.common.transport.util.SslUtil;
43 43 import org.thingsboard.server.gen.transport.TransportProtos;
  44 +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
44 45 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
45 46 import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials;
46 47 import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials;
... ... @@ -61,6 +62,7 @@ import java.util.concurrent.TimeUnit;
61 62
62 63 @Slf4j
63 64 @Component
  65 +@TbLwM2mTransportComponent
64 66 @RequiredArgsConstructor
65 67 public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVerifier {
66 68
... ...
... ... @@ -228,29 +228,27 @@ public class JsonConverter {
228 228 private static KeyValueProto buildNumericKeyValueProto(JsonPrimitive value, String key) {
229 229 String valueAsString = value.getAsString();
230 230 KeyValueProto.Builder builder = KeyValueProto.newBuilder().setKey(key);
231   - if (valueAsString.contains("e") || valueAsString.contains("E")) {
232   - //TODO: correct value conversion. We should make sure that if the value can't fit into Long or Double, we should send String
233   - var bd = new BigDecimal(valueAsString);
234   - if (bd.stripTrailingZeros().scale() <= 0) {
235   - try {
236   - return builder.setType(KeyValueType.LONG_V).setLongV(bd.longValueExact()).build();
237   - } catch (ArithmeticException e) {
238   - return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(bd.doubleValue()).build();
  231 + var bd = new BigDecimal(valueAsString);
  232 + if (bd.stripTrailingZeros().scale() <= 0) {
  233 + try {
  234 + return builder.setType(KeyValueType.LONG_V).setLongV(bd.longValueExact()).build();
  235 + } catch (ArithmeticException e) {
  236 + if (isTypeCastEnabled) {
  237 + return builder.setType(KeyValueType.STRING_V).setStringV(bd.toPlainString()).build();
  238 + } else {
  239 + throw new JsonSyntaxException("Big integer values are not supported!");
239 240 }
240   - } else {
241   - return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(bd.doubleValue()).build();
242 241 }
243   - } else if (valueAsString.contains(".")) {
244   - return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(value.getAsDouble()).build();
245 242 } else {
246   - try {
247   - long longValue = Long.parseLong(value.getAsString());
248   - return builder.setType(KeyValueType.LONG_V).setLongV(longValue).build();
249   - } catch (NumberFormatException e) {
250   - //TODO: correct value conversion. We should make sure that if the value can't fit into Long or Double, we should send String
251   - return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(new BigDecimal(valueAsString).doubleValue()).build();
  243 + if (bd.scale() <= 16) {
  244 + return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(bd.doubleValue()).build();
  245 + } else if (isTypeCastEnabled) {
  246 + return builder.setType(KeyValueType.STRING_V).setStringV(bd.toPlainString()).build();
  247 + } else {
  248 + throw new JsonSyntaxException("Big integer values are not supported!");
252 249 }
253 250 }
  251 +
254 252 }
255 253
256 254 public static TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(JsonElement json, int requestId) throws JsonSyntaxException {
... ... @@ -261,27 +259,24 @@ public class JsonConverter {
261 259 private static void parseNumericValue(List<KvEntry> result, Entry<String, JsonElement> valueEntry, JsonPrimitive value) {
262 260 String valueAsString = value.getAsString();
263 261 String key = valueEntry.getKey();
264   - if (valueAsString.contains("e") || valueAsString.contains("E")) {
265   - //TODO: correct value conversion. We should make sure that if the value can't fit into Long or Double, we should send String
266   - var bd = new BigDecimal(valueAsString);
267   - if (bd.stripTrailingZeros().scale() <= 0) {
268   - try {
269   - result.add(new LongDataEntry(key, bd.longValueExact()));
270   - } catch (ArithmeticException e) {
271   - result.add(new DoubleDataEntry(key, bd.doubleValue()));
  262 + var bd = new BigDecimal(valueAsString);
  263 + if (bd.stripTrailingZeros().scale() <= 0) {
  264 + try {
  265 + result.add(new LongDataEntry(key, bd.longValueExact()));
  266 + } catch (ArithmeticException e) {
  267 + if (isTypeCastEnabled) {
  268 + result.add(new StringDataEntry(key, bd.toPlainString()));
  269 + } else {
  270 + throw new JsonSyntaxException("Big integer values are not supported!");
272 271 }
273   - } else {
274   - result.add(new DoubleDataEntry(key, bd.doubleValue()));
275 272 }
276   - } else if (valueAsString.contains(".")) {
277   - result.add(new DoubleDataEntry(key, value.getAsDouble()));
278 273 } else {
279   - try {
280   - long longValue = Long.parseLong(value.getAsString());
281   - result.add(new LongDataEntry(key, longValue));
282   - } catch (NumberFormatException e) {
283   - //TODO: correct value conversion. We should make sure that if the value can't fit into Long or Double, we should send String
284   - result.add(new DoubleDataEntry(key, new BigDecimal(valueAsString).doubleValue()));
  274 + if (bd.scale() <= 16) {
  275 + result.add(new DoubleDataEntry(key, bd.doubleValue()));
  276 + } else if (isTypeCastEnabled) {
  277 + result.add(new StringDataEntry(key, bd.toPlainString()));
  278 + } else {
  279 + throw new JsonSyntaxException("Big integer values are not supported!");
285 280 }
286 281 }
287 282 }
... ...
... ... @@ -15,7 +15,9 @@
15 15 */
16 16
17 17 import com.google.gson.JsonParser;
  18 +import com.google.gson.JsonSyntaxException;
18 19 import org.junit.Assert;
  20 +import org.junit.Before;
19 21 import org.junit.Test;
20 22 import org.junit.runner.RunWith;
21 23 import org.mockito.junit.MockitoJUnitRunner;
... ... @@ -28,6 +30,11 @@ public class JsonConverterTest {
28 30
29 31 private static final JsonParser JSON_PARSER = new JsonParser();
30 32
  33 + @Before
  34 + public void before() {
  35 + JsonConverter.setTypeCastEnabled(true);
  36 + }
  37 +
31 38 @Test
32 39 public void testParseBigDecimalAsLong() {
33 40 var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 1E+1}"), 0L);
... ... @@ -58,4 +65,33 @@ public class JsonConverterTest {
58 65 Assert.assertEquals(11L, result.get(0L).get(0).getLongValue().get().longValue());
59 66 }
60 67
  68 + @Test
  69 + public void testParseBigDecimalAsStringOutOfLongRange() {
  70 + var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 9.9701010061400066E19}"), 0L);
  71 + Assert.assertEquals("99701010061400066000", result.get(0L).get(0).getStrValue().get());
  72 + }
  73 +
  74 + @Test
  75 + public void testParseBigDecimalAsStringOutOfLongRange2() {
  76 + var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 99701010061400066001}"), 0L);
  77 + Assert.assertEquals("99701010061400066001", result.get(0L).get(0).getStrValue().get());
  78 + }
  79 +
  80 + @Test
  81 + public void testParseBigDecimalAsStringOutOfLongRange3() {
  82 + var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 1E19}"), 0L);
  83 + Assert.assertEquals("10000000000000000000", result.get(0L).get(0).getStrValue().get());
  84 + }
  85 +
  86 + @Test(expected = JsonSyntaxException.class)
  87 + public void testParseBigDecimalOutOfLongRangeWithoutParsing() {
  88 + JsonConverter.setTypeCastEnabled(false);
  89 + JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 89701010051400054084}"), 0L);
  90 + }
  91 +
  92 + @Test(expected = JsonSyntaxException.class)
  93 + public void testParseBigDecimalOutOfLongRangeWithoutParsing2() {
  94 + JsonConverter.setTypeCastEnabled(false);
  95 + JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 9.9701010061400066E19}"), 0L);
  96 + }
61 97 }
... ...
... ... @@ -63,7 +63,7 @@ BEGIN
63 63 into max_customer_ttl;
64 64 max_ttl := GREATEST(system_ttl, max_customer_ttl, max_tenant_ttl);
65 65 if max_ttl IS NOT NULL AND max_ttl > 0 THEN
66   - date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - (max_ttl / 1000));
  66 + date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - max_ttl);
67 67 partition_by_max_ttl_date := get_partition_by_max_ttl_date(partition_type, date);
68 68 RAISE NOTICE 'Partition by max ttl: %', partition_by_max_ttl_date;
69 69 IF partition_by_max_ttl_date IS NOT NULL THEN
... ... @@ -104,11 +104,12 @@ BEGIN
104 104 END IF;
105 105 END IF;
106 106 END IF;
107   - END IF;
108   - IF partition_to_delete IS NOT NULL THEN
109   - RAISE NOTICE 'Partition to delete by max ttl: %', partition_to_delete;
110   - EXECUTE format('DROP TABLE %I', partition_to_delete);
111   - deleted := deleted + 1;
  107 + IF partition_to_delete IS NOT NULL THEN
  108 + RAISE NOTICE 'Partition to delete by max ttl: %', partition_to_delete;
  109 + EXECUTE format('DROP TABLE IF EXISTS %I', partition_to_delete);
  110 + partition_to_delete := NULL;
  111 + deleted := deleted + 1;
  112 + END IF;
112 113 END IF;
113 114 END LOOP;
114 115 END IF;
... ...
... ... @@ -48,6 +48,7 @@
48 48 <json-path.version>2.2.0</json-path.version>
49 49 <junit.version>4.12</junit.version>
50 50 <jupiter.version>5.7.1</jupiter.version>
  51 + <hamcrest.version>2.2</hamcrest.version>
51 52 <slf4j.version>1.7.7</slf4j.version>
52 53 <logback.version>1.2.3</logback.version>
53 54 <mockito.version>3.3.3</mockito.version>
... ... @@ -94,7 +95,7 @@
94 95 <hsqldb.version>2.5.0</hsqldb.version>
95 96 <dbunit.version>2.5.3</dbunit.version>
96 97 <spring-test-dbunit.version>1.2.1</spring-test-dbunit.version>
97   - <postgresql.driver.version>42.2.16</postgresql.driver.version>
  98 + <postgresql.driver.version>42.2.20</postgresql.driver.version>
98 99 <sonar.exclusions>org/thingsboard/server/gen/**/*,
99 100 org/thingsboard/server/extensions/core/plugin/telemetry/gen/**/*
100 101 </sonar.exclusions>
... ... @@ -1372,6 +1373,12 @@
1372 1373 <scope>test</scope>
1373 1374 </dependency>
1374 1375 <dependency>
  1376 + <groupId>org.hamcrest</groupId>
  1377 + <artifactId>hamcrest</artifactId>
  1378 + <version>${hamcrest.version}</version>
  1379 + <scope>test</scope>
  1380 + </dependency>
  1381 + <dependency>
1375 1382 <groupId>org.junit.jupiter</groupId>
1376 1383 <artifactId>junit-jupiter-params</artifactId>
1377 1384 <version>${jupiter.version}</version>
... ...