Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

package org.apache.iotdb.relational.it.schema;

import org.apache.iotdb.commons.utils.WindowsOSUtils;
import org.apache.iotdb.db.it.utils.TestUtils;
import org.apache.iotdb.isession.ITableSession;
import org.apache.iotdb.it.env.EnvFactory;
Expand All @@ -31,6 +32,7 @@

import org.apache.tsfile.enums.ColumnCategory;
import org.apache.tsfile.enums.TSDataType;
import org.apache.tsfile.external.commons.lang3.SystemUtils;
import org.apache.tsfile.write.record.Tablet;
import org.apache.tsfile.write.schema.IMeasurementSchema;
import org.apache.tsfile.write.schema.MeasurementSchema;
Expand Down Expand Up @@ -784,6 +786,11 @@ public void testConcurrentAutoCreateAndDropColumn() throws Exception {
@Test
public void testTableObjectCheck() throws Exception {
final Set<String> illegal = new HashSet<>(Arrays.asList("./", ".", "..", ".\\", "../hack"));
if (SystemUtils.IS_OS_WINDOWS) {
illegal.add("C.");
illegal.add("a:b<|");
illegal.add("COM1");
}
for (final String single : illegal) {
testObject4SingleIllegalPath(single);
}
Expand All @@ -796,21 +803,9 @@ private void testObject4SingleIllegalPath(final String illegal) throws Exception
final ITableSession session = EnvFactory.getEnv().getTableSessionConnection()) {
statement.execute("create database if not exists db2");
statement.execute("use db2");
statement.execute(String.format("create table \"%s\" ()", illegal));

try {
statement.execute(String.format("alter table \"%s\" add column a object", illegal));
fail();
} catch (final SQLException e) {
Assert.assertEquals(
String.format(
"701: When there are object fields, the tableName %s shall not be '.', '..' or contain './', '.\\'",
illegal),
e.getMessage());
}

// Test auto-create
String testObject =
// Test auto-create table
final String testObject =
System.getProperty("user.dir")
+ File.separator
+ "target"
Expand All @@ -819,7 +814,7 @@ private void testObject4SingleIllegalPath(final String illegal) throws Exception
+ File.separator
+ "object-example.pt";

List<IMeasurementSchema> schemaList = new ArrayList<>();
final List<IMeasurementSchema> schemaList = new ArrayList<>();
schemaList.add(new MeasurementSchema("a", TSDataType.STRING));
schemaList.add(new MeasurementSchema("b", TSDataType.STRING));
schemaList.add(new MeasurementSchema("c", TSDataType.INT32));
Expand All @@ -843,26 +838,46 @@ private void testObject4SingleIllegalPath(final String illegal) throws Exception
tablet.addValue(schemaList.get(2).getMeasurementName(), 0, 0);
tablet.addValue(0, 3, true, 0, Files.readAllBytes(Paths.get(testObject)));

final String expectedTableError =
String.format(
"701: When there are object fields, the tableName %s shall not be '.', '..' or contain './', '.\\'."
+ (SystemUtils.IS_OS_WINDOWS ? " " + WindowsOSUtils.OS_SEGMENT_ERROR : ""),
illegal.toLowerCase());
final String expectedObjectError =
String.format(
"701: When there are object fields, the objectName %s shall not be '.', '..' or contain './', '.\\'."
+ (SystemUtils.IS_OS_WINDOWS ? " " + WindowsOSUtils.OS_SEGMENT_ERROR : ""),
illegal.toLowerCase());

try {
session.executeNonQueryStatement("use db2");
session.insert(tablet);
} catch (final Exception e) {
Assert.assertEquals(
String.format(
"701: When there are object fields, the tableName %s shall not be '.', '..' or contain './', '.\\'",
illegal),
e.getMessage());
Assert.assertEquals(expectedTableError, e.getMessage());
}

statement.execute(String.format("create table \"%s\" ()", illegal));

try {
statement.execute(String.format("alter table \"%s\" add column a object", illegal));
fail();
} catch (final SQLException e) {
Assert.assertEquals(expectedTableError, e.getMessage());
}

// Test auto-create column
try {
session.executeNonQueryStatement("use db2");
session.insert(tablet);
} catch (final Exception e) {
Assert.assertEquals(expectedTableError, e.getMessage());
}

try {
statement.execute(String.format("create table test (\"%s\" object)", illegal));
fail();
} catch (final SQLException e) {
Assert.assertEquals(
String.format(
"701: When there are object fields, the objectName %s shall not be '.', '..' or contain './', '.\\'",
illegal),
e.getMessage());
Assert.assertEquals(expectedObjectError, e.getMessage());
}

statement.execute("create table test (a tag, b attribute, c int32, d object)");
Expand All @@ -873,11 +888,7 @@ private void testObject4SingleIllegalPath(final String illegal) throws Exception
session.executeNonQueryStatement("use db2");
session.insert(tablet);
} catch (final Exception e) {
Assert.assertEquals(
String.format(
"701: When there are object fields, the objectName %s shall not be '.', '..' or contain './', '.\\'",
illegal),
e.getMessage());
Assert.assertEquals(expectedObjectError, e.getMessage());
}

// It's OK if you don't write object
Expand All @@ -891,7 +902,8 @@ private void testObject4SingleIllegalPath(final String illegal) throws Exception
} catch (final SQLException e) {
Assert.assertEquals(
String.format(
"507: When there are object fields, the deviceId [test, %s] shall not be '.', '..' or contain './', '.\\'",
"507: When there are object fields, the deviceId [test, %s] shall not be '.', '..' or contain './', '.\\'."
+ (SystemUtils.IS_OS_WINDOWS ? " " + WindowsOSUtils.OS_SEGMENT_ERROR : ""),
illegal),
e.getMessage());
}
Expand All @@ -900,11 +912,7 @@ private void testObject4SingleIllegalPath(final String illegal) throws Exception
statement.execute(String.format("alter table test add column \"%s\" object", illegal));
fail();
} catch (final SQLException e) {
Assert.assertEquals(
String.format(
"701: When there are object fields, the objectName %s shall not be '.', '..' or contain './', '.\\'",
illegal),
e.getMessage());
Assert.assertEquals(expectedObjectError, e.getMessage());
}

statement.execute("drop database db2");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ private Pair<String, TsTable> parseTable4CreateTableOrView(
final TsTableColumnCategory category = columnDefinition.getColumnCategory();
final String columnName = columnDefinition.getName().getValue();
final TSDataType dataType = getDataType(columnDefinition.getType());
hasObject |= dataType.equals(TSDataType.OBJECT);
hasObject |= dataType == TSDataType.OBJECT;
final String comment = columnDefinition.getComment();
if (checkTimeColumnIdempotent(category, columnName, dataType, comment, table)
&& !hasTimeColumn) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
package org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher;

import org.apache.iotdb.commons.exception.IoTDBException;
import org.apache.iotdb.commons.exception.IoTDBRuntimeException;
import org.apache.iotdb.commons.exception.MetadataException;
import org.apache.iotdb.commons.schema.table.InsertNodeMeasurementInfo;
import org.apache.iotdb.commons.schema.table.TreeViewSchema;
import org.apache.iotdb.commons.schema.table.TsTable;
Expand Down Expand Up @@ -629,6 +631,7 @@ public TsTable toTsTable(InsertNodeMeasurementInfo measurementInfo) {
return tsTable;
}

boolean hasObject = false;
for (int i = 0; i < measurements.length; i++) {
if (measurements[i] == null) {
continue;
Expand Down Expand Up @@ -657,9 +660,17 @@ public TsTable toTsTable(InsertNodeMeasurementInfo measurementInfo) {
throw new ColumnCreationFailException(
"Cannot create column " + columnName + " datatype is not provided");
}

hasObject |= dataType == TSDataType.OBJECT;
tsTable.addColumnSchema(generateColumnSchema(category, columnName, dataType, null, null));
}
if (hasObject) {
try {
tsTable.checkTableNameAndObjectNames4Object();
} catch (final MetadataException e) {
throw new IoTDBRuntimeException(
e.getMessage(), TSStatusCode.SEMANTIC_ERROR.getStatusCode());
}
}
return tsTable;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@
import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema;
import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchemaUtil;
import org.apache.iotdb.commons.utils.CommonDateTimeUtils;
import org.apache.iotdb.commons.utils.WindowsOSUtils;
import org.apache.iotdb.rpc.TSStatusCode;

import com.google.common.collect.ImmutableList;
import org.apache.tsfile.enums.TSDataType;
import org.apache.tsfile.external.commons.lang3.SystemUtils;
import org.apache.tsfile.utils.Pair;
import org.apache.tsfile.utils.ReadWriteIOUtils;

Expand Down Expand Up @@ -71,7 +73,7 @@ public class TsTable {
public static final String TTL_PROPERTY = "ttl";
public static final Set<String> TABLE_ALLOWED_PROPERTIES = Collections.singleton(TTL_PROPERTY);
private static final String OBJECT_STRING_ERROR =
"When there are object fields, the %s %s shall not be '.', '..' or contain './', '.\\'";
"When there are object fields, the %s %s shall not be '.', '..' or contain './', '.\\'.";
protected String tableName;

private final Map<String, TsTableColumnSchema> columnSchemaMap = new LinkedHashMap<>();
Expand Down Expand Up @@ -435,15 +437,21 @@ && isInvalid4ObjectType(schema.getColumnName())) {
}
}

public static boolean isInvalid4ObjectType(final String column) {
return column.equals(".")
|| column.equals("..")
|| column.contains("./")
|| column.contains(".\\");
public static boolean isInvalid4ObjectType(final String path) {
return path.equals(".")
|| path.equals("..")
|| path.contains("./")
|| path.contains(".\\")
|| !WindowsOSUtils.isLegalPathSegment4Windows(path);
}

public static String getObjectStringError(final String columnType, final String columnName) {
return String.format(OBJECT_STRING_ERROR, columnType, columnName);
return String.format(
SystemUtils.IS_OS_WINDOWS
? OBJECT_STRING_ERROR + " " + WindowsOSUtils.OS_SEGMENT_ERROR
: OBJECT_STRING_ERROR,
columnType,
columnName);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.iotdb.commons.utils;

import org.apache.tsfile.external.commons.lang3.SystemUtils;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class WindowsOSUtils {
private static final String ILLEGAL_WINDOWS_CHARS = "\\/:*?\"<>|";
private static final Set<String> ILLEGAL_WINDOWS_NAMES =
new HashSet<>(Arrays.asList("CON", "PRN", "AUX", "NUL", "COM1-COM9, LPT1-LPT9"));

static {
for (int i = 0; i < 10; ++i) {
ILLEGAL_WINDOWS_NAMES.add("COM" + i);
ILLEGAL_WINDOWS_NAMES.add("LPT" + i);
}
}

public static final String OS_SEGMENT_ERROR =
String.format(
"In Windows System, the path shall not contains %s, equals one of %s, or ends with '.' or ' '.",
ILLEGAL_WINDOWS_CHARS, ILLEGAL_WINDOWS_NAMES);

public static boolean isLegalPathSegment4Windows(final String pathSegment) {
if (!SystemUtils.IS_OS_WINDOWS) {
return true;
}
for (final char illegalChar : ILLEGAL_WINDOWS_CHARS.toCharArray()) {
if (pathSegment.indexOf(illegalChar) != -1) {
return false;
}
}
if (pathSegment.endsWith(".") || pathSegment.endsWith(" ")) {
return false;
}
for (final String illegalName : ILLEGAL_WINDOWS_NAMES) {
if (pathSegment.equalsIgnoreCase(illegalName)) {
return false;
}
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.iotdb.commons.utils;

import org.apache.tsfile.external.commons.lang3.SystemUtils;
import org.junit.Assert;
import org.junit.Test;

import static org.apache.iotdb.commons.utils.WindowsOSUtils.isLegalPathSegment4Windows;

public class WindowsOSUtilsTest {
@Test
public void testIllegalDetection() {
if (!SystemUtils.IS_OS_WINDOWS) {
return;
}
Assert.assertTrue(isLegalPathSegment4Windows("abc"));
Assert.assertTrue(isLegalPathSegment4Windows(".A!"));

Assert.assertFalse(isLegalPathSegment4Windows("C."));
Assert.assertFalse(isLegalPathSegment4Windows("a:b<|"));
Assert.assertFalse(isLegalPathSegment4Windows("COM1"));
}
}