浏览代码

[analyser] Add checkSelectStar util

Note: we might want to refactor at some point:

    const autocompleter = await sqlParserRepository.getAutocompleteParser(dialect);
    const parsedStatement = autocompleter.parseSql(statement + ' ', '');
Romain Rigaux 4 年之前
父节点
当前提交
d6bd874626

+ 19 - 0
desktop/core/src/desktop/js/catalog/optimizer/SqlAnalyser.test.ts

@@ -55,4 +55,23 @@ describe('SqlAnalyzer.ts', () => {
       expect(isMissingLimit).toBeFalsy();
     });
   });
+
+  describe('checkSelectStar', () => {
+    it('Should detect a SELECT *', async () => {
+      const isMissingLimit = await new SqlAnalyzer(connectorA).checkSelectStar(
+        'SELECT * FROM employee',
+        'hive'
+      );
+
+      expect(isMissingLimit).toBeTruthy();
+    });
+    it('Should not warning from a non SELECT *', async () => {
+      const isMissingLimit = await new SqlAnalyzer(connectorA).checkSelectStar(
+        'SELECT name FROM employee',
+        'hive'
+      );
+
+      expect(isMissingLimit).toBeFalsy();
+    });
+  });
 });

+ 27 - 0
desktop/core/src/desktop/js/catalog/optimizer/SqlAnalyzer.ts

@@ -74,6 +74,18 @@ export default class SqlAnalyzer implements Optimizer {
           ]
         : [];
 
+      const isSelectStar = await this.checkSelectStar(snippet.statement, this.connector.dialect);
+      if (isSelectStar) {
+        hints.push(
+          {
+            riskTables: [],
+            riskAnalysis: I18n('Query doing a SELECT *'), // Could be triggered only if column number > 10 (todo in Validator API)
+            riskId: 18,
+            risk: 'low',
+            riskRecommendation: I18n('Select only a subset of columns instead of all of them')
+          }
+        );
+
       try {
         const apiResponse = await apiPromise;
         if (apiResponse.query_complexity && apiResponse.query_complexity.hints) {
@@ -108,6 +120,21 @@ export default class SqlAnalyzer implements Optimizer {
     );
   }
 
+  async checkSelectStar(statement: string, dialect: string): Promise<boolean> {
+    const autocompleter = await sqlParserRepository.getAutocompleteParser(dialect);
+    const parsedStatement = autocompleter.parseSql(statement + ' ', '');
+
+    return (
+      parsedStatement.locations.some(
+        location => location.type === 'statementType' && location.identifier === 'SELECT'
+      ) &&
+      parsedStatement.locations.some(location => {
+        return location.type === 'selectList' && !location.missing;
+      }) &&
+      parsedStatement.locations.some(location => location.type === 'asterisk')
+    );
+  }
+
   fetchTopJoins(options: PopularityOptions): CancellablePromise<TopJoins> {
     const apiPromise = this.apiStrategy.fetchTopJoins(options);