001package gudusoft.gsqlparser.resolver;
002
003import gudusoft.gsqlparser.*;
004import gudusoft.gsqlparser.compiler.*;
005import gudusoft.gsqlparser.nodes.*;
006import gudusoft.gsqlparser.stmt.*;
007import gudusoft.gsqlparser.stmt.oracle.*;
008import gudusoft.gsqlparser.util.TBuiltFunctionUtil;
009
010import java.util.ArrayList;
011import java.util.Iterator;
012import java.util.Set;
013import java.util.Stack;
014
015/**
016 * TAttributeResolver 的核心职责是为SQL语句中出现的每一个列找到其所属的表。
017 * 
018 * 工作原理:
019 * 1. 遍历SQL语句中的所有列引用(TObjectName)
020 * 2. 对每个列,在其可见范围内搜索可能的源表
021 * 3. 建立列和表之间的对应关系
022 * 
023 * 列查找规则:
024 * 1. 无表限定列(column):
025 *    - 在当前SELECT的FROM子句中所有表中查找
026 *    - 如果多个表都有这个列,标记为不明确
027 * 
028 * 2. 带表限定列(table.column):
029 *    - 在FROM子句中查找指定的表
030 *    - 检查该表是否包含指定的列
031 * 
032 * 3. 子查询中的列:
033 *    - 先在子查询的FROM子句中查找
034 *    - 如果未找到,根据子查询类型决定是否查找外层查询
035 * 
036 * 查找结果存储:
037 * - 在TObjectName.sourceTable中存储找到的表
038 * - 在TObjectName.candidateTables中存储所有可能的表
039 */
040public class TAttributeResolver extends TParseTreeVisitor {
041    private TContext globalScope;
042    private TStatementList sqlStatements;
043    private Stack<TScope> scopeStack = new Stack<>();
044    private final TSQLResolver resolver;
045    private EDbVendor dbVendor = EDbVendor.dbvoracle;
046
047
048
049    public TAttributeResolver(TStatementList sqls, TContext scope, TSQLResolver resolver) {
050        this.globalScope = scope;
051        this.sqlStatements = sqls;
052        this.scopeStack = new Stack<>();
053        this.resolver = resolver;
054        scopeStack.push(globalScope);
055        if (sqlStatements.size() > 0) {
056            dbVendor = sqlStatements.get(0).dbvendor;
057        }
058    }
059
060    public void resolve() {
061      //  System.out.println("==== Start resolving attributes:");
062//        System.out.println("==== SQL Env:");
063//        System.out.println(globalScope.getSqlEnv().toString());
064        for (int i = 0; i < sqlStatements.size(); i++) {
065            //System.out.println("\n==== Start SQL: "+i);
066            sqlStatements.get(i).acceptChildren(this);
067        }
068    }
069
070    
071
072    public void preVisit(TSelectSqlStatement stmt) {
073        // 如果是在 from clause 中出现的 subquery, 它的 parent scope 不能是之前进stack的select语句
074        // SELECT col_1, col_2
075        //FROM (
076        //    select *
077        //    FROM table_a
078        //  ) a
079
080        // 当上例中 from clause 中的 subquery 入stack时,它的parent scope 不能为整体的那个 select 语句
081        // 需要找到上一层的scope,可能为 global scope, 或者是在 存储过程中的 一个block
082        // 这些上层的 scope可以用来查找是否有 variable 等 symbol 和 subquery 中的 某个 identifier 相匹配
083
084        TScope parent = scopeStack.peek();
085
086//        if ((stmt.getLocation() == ESqlClause.join)||(stmt.getLocation() == ESqlClause.elTable) // from clause 中的 sub-query
087//          //   ||(stmt.isQueryOfCTE()) // cte 中的 sub-query 也不把直接的父级语句作为 parent env
088//        )
089//        {
090//           // while (( parent != null) && (parent instanceof TStmtScope) && (((TStmtScope)parent).getStmt() instanceof TSelectSqlStatement)){
091//            while (( parent != null) && (parent instanceof TStmtScope)
092//                    && (!isValidParentScopeForSubQuery(stmt,(TStmtScope)parent ))){
093//                parent = parent.getEnclosingScope();
094//            }
095//        }
096
097        while (( parent != null) && (parent instanceof TStmtScope)
098                && (!isValidParentScopeForSubQuery(stmt,(TStmtScope)parent ))){
099            parent = parent.getEnclosingScope();
100        }
101
102        if (stmt.isChildOfCombinedQuery()){
103            // union set 中的 sub-query 直接使用最顶层 select 的父级 enclosing scope
104            if (parent.getEnclosingScope() != null){
105                // 如果已经是 global scope, 就不再往上找
106                parent = parent.getEnclosingScope();
107            }
108
109            if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
110                TBaseType.log(String.format("select in union, parent scope is set to: %s",parent.getName()),TLog.DEBUG,stmt.getStartToken());
111            }
112
113            // System.out.println("select in union, parent scope is set to:"+parent.getName());
114        }
115
116        TStmtScope selectScope = new TStmtScope(parent, stmt);
117        scopeStack.push(selectScope);
118        attributeCount = 0;
119    }
120
121    boolean isValidParentScopeForSubQuery(TSelectSqlStatement subquery, TStmtScope scope){
122        if (!(scope.getStmt() instanceof TSelectSqlStatement)) return true; // 所有非 select 语句都可以是 subquery 的 parent scope
123        if (insidePivotedTable) return false;
124
125        TSelectSqlStatement select = (TSelectSqlStatement)scope.getStmt();
126//        if (subquery.isSubQueryInFromClauseCanUseParentSelectAsEnclosingScope()) return true;
127//
128//        return ! (
129//                    queryInFromClauseOfSelect(subquery,select )||(queryInsideCTEOfSelect(subquery,select))
130//                );
131
132        // cte subquery 的上层 select 不能作为 cte subquery 的父层
133        return !queryInsideCTEOfSelect(subquery,select);
134    }
135
136    boolean queryInsideCTEOfSelect(TSelectSqlStatement subquery, TSelectSqlStatement whole){
137        // 判断一个子查询是否在当前查询的cte中
138        if (whole.getCteList() == null) return false;
139
140        if (whole.getCteList().getStartToken()== null) return false;
141        TSourceToken cteStartToken = whole.getCteList().getStartToken();
142        if (whole.getCteList().getEndToken() == null) return false;
143        TSourceToken cteEndToken = whole.getCteList().getEndToken();
144
145        TSourceToken startToken = subquery.getStartToken();
146        if (startToken == null) return false;
147        if (startToken.lineNo < cteStartToken.lineNo) return false;
148        if ((startToken.lineNo == cteStartToken.lineNo) && (startToken.columnNo < cteStartToken.columnNo)) return false;
149
150        TSourceToken endToken = subquery.getEndToken();
151        if (endToken.lineNo > cteEndToken.lineNo) return false;
152        if ((endToken.lineNo == cteEndToken.lineNo) && (endToken.columnNo>cteEndToken.columnNo)) return false;
153
154        return true;
155    }
156
157
158    public void postVisit(TSelectSqlStatement stmt) {
159        scopeStack.pop();
160        removeResolvedOrphanColumns(stmt);
161    }
162
163    public void preVisit(TMergeSqlStatement stmt) {
164        TStmtScope mergeScope = new TStmtScope(scopeStack.peek(),stmt);
165        scopeStack.push(mergeScope);
166        attributeCount = 0;
167    }
168
169    public void postVisit(TMergeSqlStatement stmt) {
170        scopeStack.pop();
171    }
172
173    public void preVisit(TDeleteSqlStatement stmt) {
174        TStmtScope deleteScope = new TStmtScope(scopeStack.peek(),stmt);
175        scopeStack.push(deleteScope);
176        attributeCount = 0;
177    }
178
179    public void postVisit(TDeleteSqlStatement stmt) {
180        scopeStack.pop();
181    }
182
183    public void preVisit(TUpdateSqlStatement stmt) {
184        TStmtScope updateScope = new TStmtScope(scopeStack.peek(),stmt);
185        scopeStack.push(updateScope);
186        attributeCount = 0;
187    }
188
189    public void postVisit(TUpdateSqlStatement stmt) {
190        scopeStack.pop();
191    }
192
193    public void preVisit(TInsertSqlStatement stmt) {
194        TStmtScope insertScope = new TStmtScope(scopeStack.peek(),stmt);
195        scopeStack.push(insertScope);
196        attributeCount = 0;
197    }
198
199    public void postVisit(TInsertSqlStatement stmt) {
200        scopeStack.pop();
201    }
202
203    public void preVisit(TCreateTableSqlStatement stmt) {
204        // create table stmt 不要入栈作为 scope,否则
205
206//        TStmtScope selectScope = new TStmtScope(scopeStack.peek(),stmt);
207//        scopeStack.push(selectScope);
208        attributeCount = 0;
209    }
210
211    public void postVisit(TCreateTableSqlStatement stmt) {
212        //scopeStack.pop();
213    }
214
215    int attributeCount = 0;
216
217    boolean supportedStmtScope(TScope scope){
218        return ((scope instanceof TStmtScope)
219                ||(scope instanceof TDeleteStmtScope)
220                || (scope instanceof TUpdateStmtScope));
221    }
222
223    boolean supportedStmt(TCustomSqlStatement stmt){
224        return (stmt.sqlstatementtype == ESqlStatementType.sstselect)
225                ||(stmt.sqlstatementtype == ESqlStatementType.sstdelete)
226                ||(stmt.sqlstatementtype == ESqlStatementType.sstupdate);
227
228    }
229
230    private boolean insidePivotedTable = false;
231    public void preVisit(TPivotedTable node){
232        insidePivotedTable = true;
233    }
234    public void postVisit(TPivotedTable node){
235        insidePivotedTable = false;
236    }
237
238    private boolean insideCrossApplyJoinExpr = false;
239    public void preVisit(TJoinExpr node){
240        insideCrossApplyJoinExpr = node.getJointype() == EJoinType.crossapply;
241    }
242
243    public void postVisit(TJoinExpr node){
244        insideCrossApplyJoinExpr = false;
245    }
246
247
248    boolean tmpB;
249    public void preVisit(TPivotClause node){
250
251        TStmtScope current = (TStmtScope)scopeStack.peek();
252        // 保留原来的状态,在post时进行恢复
253        tmpB = current.isAllowToSearchInUpLevel();
254
255        TTable table=null;
256        switch (current.getStmt().sqlstatementtype){
257            case sstselect:
258                TSelectSqlStatement selectSqlStatement  = (TSelectSqlStatement)(current.getStmt());
259                table = selectSqlStatement.getTables().getTable(0);
260                break;
261            case sstupdate:
262                TUpdateSqlStatement updateSqlStatement = (TUpdateSqlStatement)(current.getStmt());
263                for(TTable t:updateSqlStatement.getRelations()){
264                    // 获取update语句中from clause中的第一个table
265                    if (t.getEffectType() == ETableEffectType.tetSelect){
266                        table = t;
267                        break;
268                    }
269                }
270                break;
271        }
272
273        if (table != null){
274            //onlySearchThoseAttributes.addAll(table.getAttributes());
275
276            TAttributeNode.addAllNodesToList(table.getAttributes(), onlySearchThoseAttributes);
277            if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
278                TBaseType.log(String.format("Pivot clause search attributes derived from table: %s",table.getDisplayName()),TLog.DEBUG,node.getStartToken());
279            }
280        }
281
282        for(TAttributeNode node1:onlySearchThoseAttributes){
283            if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
284                TBaseType.log(String.format("\tAttributes: %s",node1.getName()),TLog.DEBUG);
285            }
286        }
287
288        current.setSourceAttributes(onlySearchThoseAttributes);
289        current.setAllowToSearchInUpLevel(false);
290    }
291    public void postVisit(TPivotClause node){
292        onlySearchThoseAttributes.clear();
293
294        TStmtScope current = (TStmtScope)scopeStack.peek();
295        // 恢复原来的状态
296        current.setSourceAttributes(null);
297        current.setAllowToSearchInUpLevel(tmpB);
298    }
299
300    public void preVisit(TMergeInsertClause node){
301
302        TStmtScope current = (TStmtScope)scopeStack.peek();
303        // 保留原来的状态,在post时进行恢复
304        tmpB = current.isAllowToSearchInUpLevel();
305
306        TMergeSqlStatement mergeSqlStatement  = (TMergeSqlStatement)(current.getStmt());
307
308        TTable table = mergeSqlStatement.getUsingTable();
309        onlySearchThoseAttributes.clear();
310        //onlySearchThoseAttributes.addAll(table.getAttributes());
311
312        TAttributeNode.addAllNodesToList(table.getAttributes(), onlySearchThoseAttributes);
313
314        if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
315            TBaseType.log(String.format("MergeInsert clause search attributes derived from using table: %s",table.getDisplayName()),TLog.DEBUG,node.getStartToken());
316            for(TAttributeNode node1:onlySearchThoseAttributes){
317                TBaseType.log(String.format("\tAttributes: %s",node1.getName()),TLog.DEBUG);
318            }
319        }
320
321        current.setSourceAttributes(onlySearchThoseAttributes);
322        current.setAllowToSearchInUpLevel(false);
323    }
324    public void postVisit(TMergeInsertClause node){
325        onlySearchThoseAttributes.clear();
326
327        TStmtScope current = (TStmtScope)scopeStack.peek();
328        // 恢复原来的状态
329        current.setSourceAttributes(null);
330        current.setAllowToSearchInUpLevel(tmpB);
331    }
332
333    public void preVisit(TObjectName attribute){
334        if (isValidatedInOldAlgorithm(attribute)) return;
335        if (isMarkedAsNotAColumn(attribute)){
336            // 在新算法中加入的校验,如果判断不是一个 column(一般为函数参数中有特别含义的关键字)
337            // 可以从原来的 stmt 的 OrphanColumns 列表中移除,以提高准确性
338            if ((scopeStack.peek() instanceof TStmtScope)) {
339                TStmtScope current = (TStmtScope)scopeStack.peek();
340                TCustomSqlStatement stmt = current.getStmt();
341                if (stmt.getOrphanColumns().removeElement(attribute)){
342                    if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
343                        TBaseType.log(String.format("Remove fake column <%s> find in old algorithm",attribute.toString()),TLog.WARNING,attribute);
344                    }
345                }
346            }
347            return;
348        }
349
350        // check Oracle function in package
351
352        if (isColumn(attribute)){
353            if (!(scopeStack.peek() instanceof TStmtScope)) return;
354            TStmtScope current = (TStmtScope)scopeStack.peek();
355            // reset temporary status values
356            attribute.searchLevel = 0;
357            // remove this line since v3.0.3.4, to keep candidate tables for column which maybe retrieved later
358            // in order to find out how many candidate tables for this column
359            // https://www.sqlparser.com/bugs/mantisbt/view.php?id=3849
360
361           // attribute.getCandidateTables().clear();
362
363            attribute.getCandidateAttributeNodes().clear();
364
365            // if (attribute.getNumberOfPart() > 2){
366            //     TBaseType.log(String.format("Resolve attribute: %s includes %d parts", attribute.toString(), attribute.getNumberOfPart()), TLog.DEBUG, attribute);
367            //     for(int i=0;i<current.getStmt().getTables().size();i++){
368            //         TBaseType.log(String.format("\tTable: %s", current.getStmt().getTables().getTable(i).getDisplayName()), TLog.DEBUG, attribute);
369            //     }
370            // }
371            int originalSate =  attribute.getValidate_column_status();
372            current.resolve(attribute);
373            if (attribute.getValidate_column_status() != originalSate){
374                resolver.reportNewColumns(1);
375            }
376        }
377    }
378
379    public void resolveInThoseRelations(TObjectName attribute, ArrayList<TTable> relations){
380
381    }
382
383    private ArrayList<TAttributeNode> onlySearchThoseAttributes = new ArrayList<>();// 有些 clause 中的 column 只在指定的 table 中查找
384
385//    void collectAttributeFromSubQuery(TTable node, TSelectSqlStatement subquery,String prefix){
386//
387//        int i = 0;
388//        if (subquery.getResultColumnList() != null) {
389//            for(TResultColumn column: subquery.getResultColumnList()){
390//                if (column.getDisplayName().endsWith("*")){
391//                    TObjectName objectName = column.getExpr().getObjectOperand();
392//                    for(TAttributeNode attributeNode:objectName.getAttributeNodesDerivedFromFromClause()){
393//                        node.getAttributes().add(new TAttributeNode( prefix + attributeNode.getLastPartOfName() ,node,column,i));
394//                    }
395//                }else{
396//                    node.getAttributes().add(new TAttributeNode(prefix +column.getDisplayName(),node,column,i));
397//                }
398//                i++;
399//            }
400//        }
401//    }
402
403
404
405    public void postVisit(TTable node) {
406        if (node.isResolved()){
407            return;
408        }
409
410        switch (node.getTableType()){
411            case objectname:
412//                if (node.isCTEName()){
413//                    // 这是一个指向 CTE 的 table ref,根据 CTE 生成该 table ref自己的 attribute
414//                    for(TAttributeNode node1:node.getCTE().getAttributes()){
415//                        node.getAttributes().add(new TAttributeNode( node.getDisplayName() +"."+node1.getLastPartOfName() ,node,node1.getSubLevelResultColumn()));
416//                    }
417//
418////                    for(TAttributeNode node1:node.getAttributes()){
419////                        TBaseType.log(String.format("init cte ref attribute: %s, sub result column is: %s (%d,%d)"
420////                                    ,node1.getName(),node1.getSubLevelResultColumn().toString(),node1.getSubLevelResultColumn().getStartToken().lineNo,
421////                                        node1.getSubLevelResultColumn().getStartToken().columnNo)
422////                                ,TLog.DEBUG,node.getTableName());
423////                    }
424//                }
425                break;
426            case subquery:
427//                // 完成 sub-query 类型的 table 的 attributeNode 的收集,以供 attribute resolve 时使用。
428//                String prefix = "";
429//                if (node.getAliasClause() != null){
430//                    prefix = node.getAliasClause().toString()+".";
431//                }
432//
433//                node.initAttributesFromSubquery(node.getSubquery(),prefix);
434//
435//                TBaseType. log(String.format("Prepare attributes for table: %s",node.getDisplayName()), TLog.DEBUG,node.getStartToken());
436//                for(TAttributeNode a:node.getAttributes()){
437//                    TBaseType.log(String.format("\tAttriubte: %s",a.getName()),TLog.DEBUG,node.getStartToken());
438//                }
439                break;
440
441        }
442
443        // can't use reserved word as table alias
444        if (node.getAliasClause() != null){
445            if (node.getAliasClause().getAliasName() != null){
446                if (node.getAliasClause().getAliasName().getStartToken().tokencode == TBaseType.rrw_where){
447                    System.out.println("Where can't be used as table alias");
448                }
449            }
450        }
451    }
452
453    public void preVisit(TFunctionCall functionCall){
454        if (functionCall.getArgs() == null) return;
455        Set<Integer> argPos = TBuiltFunctionUtil.argumentsIncludeKeyword(functionCall.dbvendor,functionCall.getFunctionName().toString());
456        if (argPos == null) return;
457        Iterator<Integer> posIterator = argPos.iterator();
458        while(posIterator.hasNext()){
459            int p = posIterator.next();
460            if (functionCall.getArgs().size() >= p){
461                 markObjectInExprNotAValidColumn(functionCall.getArgs().getExpression(p-1));
462            }
463        }
464    }
465
466
467    
468    public void preVisit(TPlsqlCreatePackage stmt) {
469        TPlsqlCreatePackageScope createPackageScope = new TPlsqlCreatePackageScope(scopeStack.peek(),stmt);
470        scopeStack.push(createPackageScope);
471        // System.out.println("preVisit TPlsqlCreatePackage");
472        // System.out.println(stmt.getPackageName().toString());
473        //createPackageScope.addSymbol(new TVariable(stmt.getPackageName(),stmt));
474        createPackageScope.setLabelName(stmt.getPackageName());
475        for(TCustomSqlStatement body:stmt.getDeclareStatements()){
476            if (body instanceof TPlsqlCreateProcedure){
477                TObjectName routineName = ((TPlsqlCreateProcedure)(body)).getProcedureName();
478
479                //TObjectName var = TObjectName.createObjectName(stmt.dbvendor,EDbObjectType.variable,new TSourceToken(stmt.getPackageName().toString()+"."+((TPlsqlCreateProcedure)(body)).getProcedureName().toString()));
480                createPackageScope.addSymbol(new TVariable(routineName,stmt));
481            }else if (body instanceof TPlsqlCreateFunction){
482                //TObjectName var = TObjectName.createObjectName(stmt.dbvendor,EDbObjectType.variable,new TSourceToken(stmt.getPackageName().toString()+"."+((TPlsqlCreateFunction)(body)).getFunctionName().toString()));
483                TObjectName routineName = ((TPlsqlCreateFunction)(body)).getFunctionName();
484                createPackageScope.addSymbol(new TVariable(routineName,stmt));
485            }
486        }
487
488        //createPackageScope.printSymbols("");
489      
490    }
491
492    void removeResolvedOrphanColumns(TCustomSqlStatement stmt){
493        for(int i=stmt.getOrphanColumns().size()-1;i>=0;i--){
494            TObjectName objectName = stmt.getOrphanColumns().getObjectName(i);
495            if (objectName.getResolveStatus() == TBaseType.RESOLVED_AND_FOUND){
496               boolean b = stmt.getOrphanColumns().removeElement(objectName);
497            }
498        }
499
500        for(int i=stmt.getSyntaxHints().size()-1;i>=0;i--){
501            TSyntaxError hint = stmt.getSyntaxHints().get(i);
502            if (hint.objectName != null && hint.objectName.getResolveStatus() == TBaseType.RESOLVED_AND_FOUND){
503                stmt.getSyntaxHints().remove(i);
504            }
505        }
506    }
507
508    public void postVisit(TPlsqlCreatePackage stmt) {
509        removeResolvedOrphanColumns(stmt);
510        scopeStack.pop();
511    } 
512
513    public void preVisit(TPlsqlCreateProcedure stmt) {
514        TStmtScope createProcedureScope = new TStmtScope(scopeStack.peek(),stmt);
515        createProcedureScope.setLabelName(stmt.getProcedureName());
516        scopeStack.push(createProcedureScope);
517    }
518
519    public void postVisit(TPlsqlCreateProcedure stmt) {
520        scopeStack.pop();
521    }
522
523    public void preVisit(TPlsqlCreateFunction stmt) {
524        TStmtScope createFunctionScope = new TStmtScope(scopeStack.peek(),stmt);
525        createFunctionScope.setLabelName(stmt.getFunctionName());
526        scopeStack.push(createFunctionScope);
527    }
528
529    public void postVisit(TPlsqlCreateFunction stmt) {
530        scopeStack.pop();
531    }    
532
533    void markObjectInExprNotAValidColumn(TExpression expr){
534        if (expr.getExpressionType() == EExpressionType.simple_object_name_t){
535            TObjectName objectName = expr.getObjectOperand();
536            objectName.setValidate_column_status(TBaseType.MARKED_NOT_A_COLUMN_IN_COLUMN_RESOLVER);
537            expr.setExpressionType(EExpressionType.simple_constant_t);
538            expr.setConstantOperand(new TConstant(ELiteralType.unknownType,objectName.getStartToken()));
539            if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
540                TBaseType.log(String.format("Mark object <%s> as not a column",objectName.toString()),TLog.DEBUG,objectName);
541            }
542        }
543        return;
544    }
545    boolean isValidatedInOldAlgorithm(TObjectName objectName){
546       return (objectName.getValidate_column_status() == TBaseType.COLUMN_LINKED_TO_TABLE_IN_OLD_ALGORITHM);
547    }
548
549    boolean isMarkedAsNotAColumn(TObjectName objectName){
550        return (objectName.getValidate_column_status() == TBaseType.MARKED_NOT_A_COLUMN_IN_COLUMN_RESOLVER);
551    }
552
553    boolean isColumn(TObjectName objectName){
554        return !(
555                (objectName.getDbObjectType() == EDbObjectType.table)
556                        ||(objectName.getDbObjectType() == EDbObjectType.alias)
557                        ||(objectName.getDbObjectType() == EDbObjectType.attribute)
558                        ||(objectName.getDbObjectType() == EDbObjectType.column_alias)
559                        ||(objectName.getDbObjectType() == EDbObjectType.constraint)
560                        ||(objectName.getDbObjectType() == EDbObjectType.cte)
561                        ||(objectName.getDbObjectType() == EDbObjectType.cursor)
562                        ||(objectName.getDbObjectType() == EDbObjectType.database)
563                        ||(objectName.getDbObjectType() == EDbObjectType.function)
564                        ||(objectName.getDbObjectType() == EDbObjectType.index)
565                        ||(objectName.getDbObjectType() == EDbObjectType.label)
566                        ||(objectName.getDbObjectType() == EDbObjectType.library)
567                        ||(objectName.getDbObjectType() == EDbObjectType.materializedView)
568                        ||(objectName.getDbObjectType() == EDbObjectType.method)
569                        ||(objectName.getDbObjectType() == EDbObjectType.parameter)
570                        ||(objectName.getDbObjectType() == EDbObjectType.plsql_package)
571                        ||(objectName.getDbObjectType() == EDbObjectType.property)
572                        ||(objectName.getDbObjectType() == EDbObjectType.procedure)
573                        ||(objectName.getDbObjectType() == EDbObjectType.table_alias)
574                        ||(objectName.getDbObjectType() == EDbObjectType.transaction)
575                        ||(objectName.getDbObjectType() == EDbObjectType.trigger)
576                        ||(objectName.getDbObjectType() == EDbObjectType.sequence)
577                        ||(objectName.getDbObjectType() == EDbObjectType.user_defined_type)
578                        ||(objectName.getDbObjectType() == EDbObjectType.variable)
579                        ||(objectName.getDbObjectType() == EDbObjectType.view)
580                        ||(!objectName.isValidColumnName(dbVendor))
581                        ||(objectName.toString().endsWith("*"))
582        );
583    }
584}