-
Notifications
You must be signed in to change notification settings - Fork 112
Feauture/query nested fields by dot #3470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
8fc4ef8
08db7f2
645af07
4188334
15ada23
485f3a6
0b5dc9f
c1ce4f8
4f43a62
e8ab22d
7e00c7b
715c815
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Разыменование ссылочных полей запроса через точку (QueryNestedFieldsByDot) | ||
|
||
<!-- Блоки выше заполняются автоматически, не трогать --> | ||
## Описание диагностики | ||
|
||
Диагностика позволяет контролировать разыменование ссылочных полей через точку в тексте запроса 1С. | ||
Задача данной диагностики - предотвратить излишние неявные соединения между таблицами | ||
и как следствие - повысить производительность исполнения запроса к БД. | ||
|
||
## Примеры | ||
1. Базовое разыменование ссылочных полей в выборке (во временную таблицу или в результат запроса) | ||
`ЗаказКлиентаТовары.Ссылка.Организация КАК Организация` | ||
2. Разыменование ссылочных полей в соединениях таблиц | ||
`ВТ_РасчетыСКлиентами КАК ВТ_РасчетыСКлиентами | ||
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ДанныеЗаказовКлиента КАК ВТ_ДанныеЗаказовКлиента | ||
ПО ВТ_РасчетыСКлиентами.АналитикаУчетаПоПартнерам.Партнер = ВТ_ДанныеЗаказовКлиента.Партнер` | ||
3. Разыменование ссылочных полей в виртуальных таблицах | ||
`РегистрНакопления.РасчетыСКлиентами.Обороты( | ||
&НачалоПериода, | ||
&КонецПериода, | ||
, | ||
(АналитикаУчетаПоПартнерам.Партнер) В ...` | ||
4. Конструкция "ВЫРАЗИТЬ" с разыменованием получаемого поля | ||
`ВЫРАЗИТЬ(ВТ_ПланОтгрузок.ДокументПлан КАК Документ.ЗаказКлиента).Валюта.Наценка` | ||
5. Разыменование ссылочных полей в секции "ГДЕ" | ||
`ГДЕ азКлиентаТовары.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода` | ||
|
||
<!-- В данном разделе приводятся примеры, на которые диагностика срабатывает, а также можно привести пример, как можно исправить ситуацию --> | ||
|
||
## Источники | ||
Источник: [Разыменование ссылочных полей составного типа в языке запросов] (https://its.1c.ru/db/v8std/content/654/hdoc) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Getting objects nested fields data by dot in database query text (QueryNestedFieldsByDot) | ||
|
||
<!-- Блоки выше заполняются автоматически, не трогать --> | ||
## Description | ||
Diagnostics allows you to control the dereference of reference fields through a dot in the 1C query language. | ||
The purpose of this diagnostic is to prevent unnecessary implicit joins between tables. | ||
and as a result, improve the performance of executing a database query. | ||
|
||
## Examples | ||
1. Base dereference through a dot (in temp. db or in select query) | ||
`ЗаказКлиентаТовары.Ссылка.Организация КАК Организация` | ||
2. Dereference of fields in table join section | ||
`ВТ_РасчетыСКлиентами КАК ВТ_РасчетыСКлиентами | ||
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ДанныеЗаказовКлиента КАК ВТ_ДанныеЗаказовКлиента | ||
ПО ВТ_РасчетыСКлиентами.АналитикаУчетаПоПартнерам.Партнер = ВТ_ДанныеЗаказовКлиента.Партнер` | ||
3. Dereference of fields in virtual tables | ||
`РегистрНакопления.РасчетыСКлиентами.Обороты( | ||
&НачалоПериода, | ||
&КонецПериода, | ||
, | ||
(АналитикаУчетаПоПартнерам.Партнер) В ...` | ||
4. Dereference in cast function result fields | ||
`ВЫРАЗИТЬ(ВТ_ПланОтгрузок.ДокументПлан КАК Документ.ЗаказКлиента).Валюта.Наценка` | ||
5. Dereference of fields in WHERE section | ||
`ГДЕ азКлиентаТовары.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода` | ||
## Sources | ||
Source: [Dereference of composite type reference fields in the query language (RU)] (https://its.1c.ru/db/v8std/content/654/hdoc) |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,80 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* This file is a part of BSL Language Server. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Copyright (c) 2018-2025 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Alexey Sosnoviy <[email protected]>, Nikita Fedkin <[email protected]> and contributors | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* SPDX-License-Identifier: LGPL-3.0-or-later | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* BSL Language Server is free software; you can redistribute it and/or | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* modify it under the terms of the GNU Lesser General Public | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* License as published by the Free Software Foundation; either | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* version 3.0 of the License, or (at your option) any later version. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* BSL Language Server is distributed in the hope that it will be useful, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Lesser General Public License for more details. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* You should have received a copy of the GNU Lesser General Public | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* License along with BSL Language Server. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
package com.github._1c_syntax.bsl.languageserver.diagnostics; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import com.github._1c_syntax.bsl.parser.SDBLParser; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@DiagnosticMetadata( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type = DiagnosticType.CODE_SMELL, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
severity = DiagnosticSeverity.INFO, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
minutesToFix = 1, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
tags = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
DiagnosticTag.SQL, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
DiagnosticTag.PERFORMANCE, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
DiagnosticTag.DESIGN | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public class QueryNestedFieldsByDotDiagnostic extends AbstractSDBLListenerDiagnostic { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//Флаг обработки параметров виртуальной таблицы | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public boolean isVirtualTable = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public void enterQuery(SDBLParser.QueryContext ctx) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
isVirtualTable = false; //Сбрасываем флаг при начале обработки запроса | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
super.enterQuery(ctx); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public void exitVirtualTableParameter(SDBLParser.VirtualTableParameterContext ctx) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
isVirtualTable = true; //Взводим флаг при начале обработки параметров виртуальной таблицы | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
super.exitVirtualTableParameter(ctx); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public void enterFunctionCall(SDBLParser.FunctionCallContext ctx) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//Контролируем разыменование в функциях (ВЫРАЗИТЬ, ЕСТЬNULL и т.д.) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if(ctx.identifier != null && ctx.columnNames.size() > 1){ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
diagnosticStorage.addDiagnostic(ctx); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
super.enterFunctionCall(ctx); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public void enterColumn(SDBLParser.ColumnContext ctx) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/*Если взведен флаг обработки виртуальной таблицы | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
и определен контекст метаданных, то проверяем заполненность контекста имен колонок. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
В противном случае считаем что работаем со стандартным полем выборки или соединения | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
и выводим ошибку когда список имен колонки содержит более одного идентификатора | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if((isVirtualTable && ctx.mdoName != null && !ctx.columnNames.isEmpty()) || ctx.columnNames.size() > 1){ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
diagnosticStorage.addDiagnostic(ctx); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
super.enterColumn(ctx); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+67
to
+79
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Отсутствует защита от NullPointerException. В методе - if((isVirtualTable && ctx.mdoName != null && !ctx.columnNames.isEmpty()) || ctx.columnNames.size() > 1){
+ if((isVirtualTable && ctx.mdoName != null && ctx.columnNames != null && !ctx.columnNames.isEmpty()) ||
+ (ctx.columnNames != null && ctx.columnNames.size() > 1)){ 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
diagnosticMessage=Detected access to reference data nested field by dot in database query text | ||
diagnosticName=Getting objects nested fields data by dot in database query text |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
diagnosticMessage=Обнаружено разыменование ссылочного поля | ||
diagnosticName=Разыменование ссылочных полей запроса через точку |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
* This file is a part of BSL Language Server. | ||
* | ||
* Copyright (c) 2018-2025 | ||
* Alexey Sosnoviy <[email protected]>, Nikita Fedkin <[email protected]> and contributors | ||
* | ||
* SPDX-License-Identifier: LGPL-3.0-or-later | ||
* | ||
* BSL Language Server is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU Lesser General Public | ||
* License as published by the Free Software Foundation; either | ||
* version 3.0 of the License, or (at your option) any later version. | ||
* | ||
* BSL Language Server is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with BSL Language Server. | ||
*/ | ||
package com.github._1c_syntax.bsl.languageserver.diagnostics; | ||
|
||
import org.eclipse.lsp4j.Diagnostic; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import java.util.List; | ||
|
||
import static com.github._1c_syntax.bsl.languageserver.util.Assertions.assertThat; | ||
|
||
class QueryNestedFieldsByDotDiagnosticTest extends AbstractDiagnosticTest<QueryNestedFieldsByDotDiagnostic> { | ||
QueryNestedFieldsByDotDiagnosticTest() { | ||
super(QueryNestedFieldsByDotDiagnostic.class); | ||
} | ||
|
||
@Test | ||
void test() { | ||
|
||
List<Diagnostic> diagnostics = getDiagnostics(); | ||
|
||
assertThat(diagnostics).hasSize(12); | ||
assertThat(diagnostics, true) | ||
.hasRange(21, 3, 21, 40) //Ошибка №1 | ||
.hasRange(22, 3, 22, 39) //Ошибка №1 | ||
.hasRange(23, 3, 23, 36) //Ошибка №1 | ||
.hasRange(24, 3, 24, 43) //Ошибка №1 | ||
.hasRange(29, 3, 29, 33) //Ошибка №7 | ||
.hasRange(53, 6, 53, 39) //Ошибка №3 | ||
.hasRange(53, 41, 53, 77) //Ошибка №3 | ||
.hasRange(53, 79, 53, 116) //Ошибка №3 | ||
.hasRange(101, 7, 101, 61) //Ошибка №2 | ||
.hasRange(102, 7, 102, 64) //Ошибка №2 | ||
.hasRange(103, 7, 103, 65) //Ошибка №2 | ||
.hasRange(115, 3, 115, 82); //Ошибка №6 | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Отсутствует защита от NullPointerException.
В методе
enterFunctionCall
условиеctx.identifier != null && ctx.columnNames.size() > 1
может вызвать NullPointerException, если ctx.columnNames равно null. Рекомендуется добавить дополнительную проверку.📝 Committable suggestion