diff --git a/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/Messages.java b/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/Messages.java index 3848c411..d11703fb 100644 --- a/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/Messages.java +++ b/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/Messages.java @@ -39,6 +39,7 @@ final class Messages public static String JoinToSubQuery_Query_join_to_sub_query_not_allowed; public static String JoinToSubQuery_title; public static String TempTableHasIndex_description; + public static String TempTableHasIndex_Exclude_table_name_pattern; public static String TempTableHasIndex_New_temporary_table_should_have_indexes; public static String TempTableHasIndex_title; static diff --git a/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/TempTableHasIndex.java b/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/TempTableHasIndex.java index 152ea7e5..793ed438 100644 --- a/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/TempTableHasIndex.java +++ b/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/TempTableHasIndex.java @@ -17,6 +17,7 @@ import static com._1c.g5.v8.dt.ql.model.QlPackage.Literals.ABSTRACT_QUERY_SCHEMA import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.ecore.EObject; +import com._1c.g5.v8.dt.common.StringUtils; import com._1c.g5.v8.dt.ql.model.AbstractQuerySchemaTable; import com._1c.g5.v8.dt.ql.model.QuerySchemaSelectQuery; import com.e1c.g5.v8.dt.check.CheckComplexity; @@ -38,6 +39,10 @@ public class TempTableHasIndex private static final String CHECK_ID = "ql-temp-table-index"; //$NON-NLS-1$ + private static final String PARAMETER_EXCLUDE_TABLE_NAME_PATTERN = "excludeObjectNamePattern"; //$NON-NLS-1$ + + private static final int MAX_TOP = 1000; + @Override public String getCheckId() { @@ -53,6 +58,8 @@ public class TempTableHasIndex .severity(IssueSeverity.MAJOR) .issueType(IssueType.PERFORMANCE) .delegate(QuerySchemaSelectQuery.class); + builder.parameter(PARAMETER_EXCLUDE_TABLE_NAME_PATTERN, String.class, StringUtils.EMPTY, + Messages.TempTableHasIndex_Exclude_table_name_pattern); } @Override @@ -60,7 +67,7 @@ public class TempTableHasIndex ICheckParameters parameters, IProgressMonitor monitor) { QuerySchemaSelectQuery selectQuery = (QuerySchemaSelectQuery)object; - if (selectQuery.getPlacementTable() == null) + if (selectQuery.getPlacementTable() == null || isTopLessThenThousand(selectQuery)) { return; } @@ -68,9 +75,33 @@ public class TempTableHasIndex if (selectQuery.getIndexes() == null || selectQuery.getIndexes().isEmpty()) { AbstractQuerySchemaTable table = selectQuery.getPlacementTable(); + String excludeTableNamePattern = parameters.getString(PARAMETER_EXCLUDE_TABLE_NAME_PATTERN); + if (excludeTableNamePattern != null && !excludeTableNamePattern.isBlank() + && table.getFullTableName().matches(excludeTableNamePattern)) + { + return; + } resultAceptor.addIssue(Messages.TempTableHasIndex_New_temporary_table_should_have_indexes, table, ABSTRACT_QUERY_SCHEMA_TABLE__TABLE_NAME); } } + private boolean isTopLessThenThousand(QuerySchemaSelectQuery selectQuery) + { + if (!selectQuery.getOperators().isEmpty() && selectQuery.getOperators().get(0).getGetRecordsCount() != null) + { + String count = selectQuery.getOperators().get(0).getGetRecordsCount(); + try + { + int top = Integer.parseInt(count); + return top < MAX_TOP; + } + catch (NumberFormatException e) + { + // do nothing + } + } + return false; + } + } diff --git a/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/messages.properties b/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/messages.properties index 58d748e6..8c359003 100644 --- a/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/messages.properties +++ b/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/messages.properties @@ -24,5 +24,6 @@ JoinToSubQuery_description=Query join with sub query JoinToSubQuery_Query_join_to_sub_query_not_allowed=Query join to sub query not allowed JoinToSubQuery_title=Query join with sub query TempTableHasIndex_description=Temporary table should have indexes +TempTableHasIndex_Exclude_table_name_pattern=Exclude table name pattern TempTableHasIndex_New_temporary_table_should_have_indexes=New temporary table should have indexes TempTableHasIndex_title=Temporary table should have indexes diff --git a/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/messages_ru.properties b/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/messages_ru.properties index c5b9aa37..4e5e1e1a 100644 --- a/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/messages_ru.properties +++ b/bundles/com.e1c.v8codestyle.ql/src/com/e1c/v8codestyle/ql/check/messages_ru.properties @@ -39,6 +39,8 @@ JoinToSubQuery_description = Соединение запроса с подзап JoinToSubQuery_title = Соединение запроса с подзапросом +TempTableHasIndex_Exclude_table_name_pattern = Выражения исключения имени таблицы + TempTableHasIndex_New_temporary_table_should_have_indexes = Новая временная таблица должна содержать индексы TempTableHasIndex_description = Временная таблица должна содержать индексы diff --git a/tests/com.e1c.v8codestyle.ql.itests/resources/temp-table-has-no-index-top.ql b/tests/com.e1c.v8codestyle.ql.itests/resources/temp-table-has-no-index-top.ql new file mode 100644 index 00000000..30b6fed7 --- /dev/null +++ b/tests/com.e1c.v8codestyle.ql.itests/resources/temp-table-has-no-index-top.ql @@ -0,0 +1,12 @@ +SELECT TOP 100000 + 1 AS Field +INTO T +; + +//////////////////////////////////////////////////////////////////////////////// +SELECT TOP 100 + T.Field +FROM + T AS T +INTO T2 +; \ No newline at end of file diff --git a/tests/com.e1c.v8codestyle.ql.itests/src/com/e1c/v8codestyle/ql/check/itests/TempTableHasIndexTest.java b/tests/com.e1c.v8codestyle.ql.itests/src/com/e1c/v8codestyle/ql/check/itests/TempTableHasIndexTest.java index 77fb8b91..cadc1233 100644 --- a/tests/com.e1c.v8codestyle.ql.itests/src/com/e1c/v8codestyle/ql/check/itests/TempTableHasIndexTest.java +++ b/tests/com.e1c.v8codestyle.ql.itests/src/com/e1c/v8codestyle/ql/check/itests/TempTableHasIndexTest.java @@ -18,6 +18,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.nio.charset.StandardCharsets; +import java.util.Map; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.emf.ecore.EObject; @@ -46,10 +47,14 @@ public class TempTableHasIndexTest private static final String FOLDER = "/resources/"; + private static final String PARAMETER_EXCLUDE_TABLE_NAME_PATTERN = "excludeObjectNamePattern"; + private TestingCheckResultAcceptor resultAcceptor; private TestingQlResultAcceptor qlResultAcceptor; + private TestingCheckParameters emptyParameters; + private TempTableHasIndex check; @Override @@ -63,6 +68,7 @@ public class TempTableHasIndexTest { resultAcceptor = new TestingCheckResultAcceptor(); qlResultAcceptor = new TestingQlResultAcceptor(); + emptyParameters = new TestingCheckParameters(Map.of(PARAMETER_EXCLUDE_TABLE_NAME_PATTERN, "")); QlBasicDelegateCheck.setResultAcceptor((o, f) -> qlResultAcceptor); check = new TempTableHasIndex(); } @@ -84,14 +90,45 @@ public class TempTableHasIndexTest EObject selectQuery = querySchema.getQueries().get(1); assertTrue(selectQuery instanceof QuerySchemaSelectQuery); - check.check(selectQuery, resultAcceptor, null, new NullProgressMonitor()); + check.check(selectQuery, resultAcceptor, emptyParameters, new NullProgressMonitor()); assertTrue(qlResultAcceptor.messages.isEmpty()); assertTrue(qlResultAcceptor.featuredMessages.isEmpty()); selectQuery = querySchema.getQueries().get(0); assertTrue(selectQuery instanceof QuerySchemaSelectQuery); - check.check(selectQuery, resultAcceptor, null, new NullProgressMonitor()); + check.check(selectQuery, resultAcceptor, emptyParameters, new NullProgressMonitor()); + + assertTrue(qlResultAcceptor.messages.isEmpty()); + assertFalse(qlResultAcceptor.featuredMessages.isEmpty()); + + } + + @Test + public void testTempTableWithoutIndexWithRecordCount() throws Exception + { + IDtProject project = dtProjectManager.getDtProject(PROJECT_NAME); + + String queryText = + new String(getClass().getResourceAsStream(FOLDER + "temp-table-has-no-index-top.ql").readAllBytes(), + StandardCharsets.UTF_8); + + QuerySchema querySchema = DcsUtil.getQuerySchema(queryText, project); + assertNotNull(querySchema); + assertEquals(2, querySchema.getQueries().size()); + + QlBasicDelegateCheck.setOwner(new QueryOwner(querySchema, null)); + EObject selectQuery = querySchema.getQueries().get(1); + assertTrue(selectQuery instanceof QuerySchemaSelectQuery); + + check.check(selectQuery, resultAcceptor, emptyParameters, new NullProgressMonitor()); + + assertTrue(qlResultAcceptor.messages.isEmpty()); + assertTrue(qlResultAcceptor.featuredMessages.isEmpty()); + + selectQuery = querySchema.getQueries().get(0); + assertTrue(selectQuery instanceof QuerySchemaSelectQuery); + check.check(selectQuery, resultAcceptor, emptyParameters, new NullProgressMonitor()); assertTrue(qlResultAcceptor.messages.isEmpty()); assertFalse(qlResultAcceptor.featuredMessages.isEmpty()); @@ -115,14 +152,14 @@ public class TempTableHasIndexTest EObject selectQuery = querySchema.getQueries().get(1); assertTrue(selectQuery instanceof QuerySchemaSelectQuery); - check.check(selectQuery, resultAcceptor, null, new NullProgressMonitor()); + check.check(selectQuery, resultAcceptor, emptyParameters, new NullProgressMonitor()); assertTrue(qlResultAcceptor.messages.isEmpty()); assertTrue(qlResultAcceptor.featuredMessages.isEmpty()); selectQuery = querySchema.getQueries().get(0); assertTrue(selectQuery instanceof QuerySchemaSelectQuery); - check.check(selectQuery, resultAcceptor, null, new NullProgressMonitor()); + check.check(selectQuery, resultAcceptor, emptyParameters, new NullProgressMonitor()); assertTrue(qlResultAcceptor.messages.isEmpty()); assertTrue(qlResultAcceptor.featuredMessages.isEmpty()); diff --git a/tests/com.e1c.v8codestyle.ql.itests/src/com/e1c/v8codestyle/ql/check/itests/TestingCheckParameters.java b/tests/com.e1c.v8codestyle.ql.itests/src/com/e1c/v8codestyle/ql/check/itests/TestingCheckParameters.java new file mode 100644 index 00000000..9c8314e8 --- /dev/null +++ b/tests/com.e1c.v8codestyle.ql.itests/src/com/e1c/v8codestyle/ql/check/itests/TestingCheckParameters.java @@ -0,0 +1,83 @@ +/** + * + */ +package com.e1c.v8codestyle.ql.check.itests; + +import java.text.MessageFormat; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import com.e1c.g5.v8.dt.check.ICheckParameters; +import com.e1c.g5.v8.dt.check.WrongParameterException; + +/** + * @author Dmitriy Marmyshev + * + */ +public class TestingCheckParameters + implements ICheckParameters +{ + private final Map data; + + public TestingCheckParameters(Map data) + { + this.data = Objects.requireNonNull(data); + } + + @Override + public int getInt(String name) + { + return get(name, Integer.class).intValue(); + } + + @Override + public long getLong(String name) + { + return get(name, Long.class).longValue(); + } + + @Override + public boolean getBoolean(String name) + { + return get(name, Boolean.class).booleanValue(); + } + + @Override + public double getDouble(String name) + { + return get(name, Double.class).doubleValue(); + } + + @Override + public String getString(String name) + { + return get(name, String.class); + } + + @Override + public Set keySet() + { + return this.data.keySet(); + } + + @Override + public String toString() + { + return this.data.toString(); + } + + private T get(String name, Class type) throws WrongParameterException + { + Object value = this.data.get(name); + if (value == null) + throw new WrongParameterException(name, "Parameter not found"); + if (type.isInstance(value)) + return type.cast(value); + if (value instanceof WrongParameterException) + throw new WrongParameterException(name, ((WrongParameterException)value).getMessage()); + throw new WrongParameterException(name, + MessageFormat.format("Parameter has a different type {0}", value.getClass().getSimpleName())); + } + +}