001package gudusoft.gsqlparser.sqlenv;
002
003import gudusoft.gsqlparser.*;
004import gudusoft.gsqlparser.compiler.TFunction;
005import gudusoft.gsqlparser.nodes.TObjectName;
006import gudusoft.gsqlparser.nodes.TTypeName;
007import gudusoft.gsqlparser.util.SQLUtil;
008
009import java.util.ArrayList;
010import java.util.HashMap;
011import java.util.List;
012
013import static gudusoft.gsqlparser.sqlenv.ESQLDataObjectType.*;
014
015/**
016 * SQL environment includes the metadata of a list of databases. The typical scenario is there is one database includes
017 * some schemas, and each schema includes some tables, views, procedures and etc.
018 * <br>
019 * <br>Database known as catalog in ANSI SQL.
020 * <br>Each catalog including a list of schemas.
021 * <br>Each schema including a list of schema objects such as table, procedure, function, trigger and more.
022 * <br>
023 * Implement your own concrete class derived from this class to get the metadata from a real database.
024 * Usually, this is done by querying the INFORMATION_SCHEMA in the {@link #initSQLEnv()} method which should be override
025 * in your own class.
026 * <br><br>
027 *
028 */
029public abstract class TSQLEnv {
030
031    public static boolean[] columnCollationCaseSensitive = {
032            false, //            dbvaccess,
033            false, //            dbvansi,
034            false, //             dbvathena
035            false,  //            dbvazuresql,
036            false,  //            dbvbigquery,
037            false,  //            dbvcouchbase,
038            false,  //            dbvdax,
039            false,  //            dbvdb2,
040            false,  //            dbvexasol,
041            false,  //            dbvfirebird,
042            false,  //            dbvgeneric,
043            false,  //            dbvgreenplum,
044            false,  //            dbvhana,
045            false,  //            dbvhive,
046            false,  //            dbvimpala,
047            false,  //            dbvinformix,
048            false,  //            dbvmdx,
049            false,  //            dbvmysql,
050            false,  //            dbvmssql,
051            false,  //            dbvnetezza,
052            false,  //            dbvodbc,
053            false,  //            dbvopenedge,
054            true,  //            dbvoracle,
055            false,  //            dbvpostgresql,
056            false,//              dbvpresto
057            false,  //            dbvredshift,
058            false,  //            dbvsnowflake,
059            false,  //            dbvsoql,
060            false,  //            dbvsparksql,
061            false,  //            dbvsybase,
062            false,  //            dbvteradata,
063            false,  //            dbvtrino
064            false,  //            dbvvertica,
065            false,  //            dbvdatabricks
066            false,  //            dbvgaussdb,
067    };
068
069    public static boolean[] functionCollationCaseSensitive = {
070            false, //            dbvaccess,
071            false, //            dbvansi,
072            false,//             dbvathena
073            false,  //            dbvazuresql,
074            false,  //            dbvbigquery,
075            false,  //            dbvcouchbase,
076            false,  //            dbvdax,
077            false,  //            dbvdb2,
078            false,  //            dbvexasol,
079            false,  //            dbvfirebird,
080            false,  //            dbvgeneric,
081            false,  //            dbvgreenplum,
082            false,  //            dbvhana,
083            false,  //            dbvhive,
084            false,  //            dbvimpala,
085            false,  //            dbvinformix,
086            false,  //            dbvmdx,
087            false,  //            dbvmysql,
088            false,  //            dbvmssql,
089            false,  //            dbvnetezza,
090            false,  //            dbvodbc,
091            false,  //            dbvopenedge,
092            true,  //            dbvoracle,
093            true,  //            dbvpostgresql,
094            false,//              dbvpresto
095            false,  //            dbvredshift,
096            false,  //            dbvsnowflake,
097            false,  //            dbvsoql,
098            false,  //            dbvsparksql,
099            false,  //            dbvsybase,
100            false,  //            dbvteradata,
101            false,  //            dbvtrino
102            false,  //            dbvvertica,
103            false,  //            dbvdatabricks,
104            false,  //            dbvgaussdb,
105    };
106    public static boolean[] tableCollationCaseSensitive = {
107            false, //            dbvaccess,
108            false, //            dbvansi,
109            false,//             dbvathena
110            false,  //            dbvazuresql,
111            false,  //            dbvbigquery,
112            false,  //            dbvcouchbase,
113            false,  //            dbvdax,
114            true,  //            dbvdb2,
115            false,  //            dbvexasol,
116            false,  //            dbvfirebird,
117            false,  //            dbvgeneric,
118            false,  //            dbvgreenplum,
119            false,  //            dbvhana,
120            false,  //            dbvhive,
121            false,  //            dbvimpala,
122            false,  //            dbvinformix,
123            false,  //            dbvmdx,
124            false,  //            dbvmysql,
125            false,  //            dbvmssql,
126            false,  //            dbvnetezza,
127            false,  //            dbvodbc,
128            false,  //            dbvopenedge,
129            true,  //            dbvoracle,
130            true,  //            dbvpostgresql,
131            false,//              dbvpresto
132            false,  //            dbvredshift,
133            false,  //            dbvsnowflake,
134            false,  //            dbvsoql,
135            false,  //            dbvsparksql,
136            false,  //            dbvsybase,
137            false,  //            dbvteradata,
138            false,  //            dbvtrino
139            false,  //            dbvvertica,
140            false,  //            dbvdatabricks,
141            false,  //            dbvgaussdb,
142    };
143
144    public static boolean[] catalogCollationCaseSensitive = {
145            false, //            dbvaccess,
146            false, //            dbvansi,
147            false,//             dbvathena
148            false,  //            dbvazuresql,
149            false,  //            dbvbigquery,
150            false,  //            dbvcouchbase,
151            false,  //            dbvdax,
152            true,  //            dbvdb2,
153            false,  //            dbvexasol,
154            false,  //            dbvfirebird,
155            false,  //            dbvgeneric,
156            false,  //            dbvgreenplum,
157            false,  //            dbvhana,
158            false,  //            dbvhive,
159            false,  //            dbvimpala,
160            false,  //            dbvinformix,
161            false,  //            dbvmdx,
162            true,  //            dbvmysql,
163            false,  //            dbvmssql,
164            false,  //            dbvnetezza,
165            false,  //            dbvodbc,
166            false,  //            dbvopenedge,
167            false,  //            dbvoracle,
168            true,  //            dbvpostgresql,
169            false,//              dbvpresto
170            false,  //            dbvredshift,
171            false,  //            dbvsnowflake,
172            false,  //            dbvsoql,
173            false,  //            dbvsparksql,
174            false,  //            dbvsybase,
175            false,  //            dbvteradata,
176            false,  //            dbvtrino
177            false,  //            dbvvertica,
178            false,  //            dbvdatabricks,
179            false,  //            dbvgaussdb,
180    };
181
182    public static boolean[]  defaultCollationCaseSensitive = {
183            false, //            dbvaccess,
184            false, //            dbvansi,
185            false,//             dbvathena
186            false,  //            dbvazuresql,
187            false,  //            dbvbigquery,
188            false,  //            dbvcouchbase,
189            false,  //            dbvdax,
190            false,  //            dbvdb2,
191            false,  //            dbvexasol,
192            false,  //            dbvfirebird,
193            false,  //            dbvgeneric,
194            false,  //            dbvgreenplum,
195            false,  //            dbvhana,
196            false,  //            dbvhive,
197            false,  //            dbvimpala,
198            false,  //            dbvinformix,
199            false,  //            dbvmdx,
200            false,  //            dbvmysql,
201            false,  //            dbvmssql,
202            false,  //            dbvnetezza,
203            false,  //            dbvodbc,
204            false,  //            dbvopenedge,
205            false,  //            dbvoracle,
206            false,  //            dbvpostgresql,
207            false,  //            dbvpresto
208            false,  //            dbvredshift,
209            false,  //            dbvsnowflake,
210            false,  //            dbvsoql,
211            false,  //            dbvsparksql,
212            false,  //            dbvsybase,
213            false,  //            dbvteradata,
214            false,  //            dbvtrino
215            false,  //            dbvvertica,
216            false,  //            dbvdatabricks,
217            false,  //            dbvgaussdb,
218    };
219
220    // public static boolean[] isAliasReferenceForbidden = {
221    //         false, // dbvaccess - MODIFIED: set to false (original value: false)
222    //         false, // dbvansi - MODIFIED: set to false (original value: false)
223    //         false, // dbvathena - MODIFIED: set to false (original value: false)
224    //         false, // dbvazuresql - MODIFIED: set to false (original value: true)
225    //         false, // dbvbigquery - MODIFIED: set to false (original value: true)
226    //         false, // dbvcouchbase - MODIFIED: set to false (original value: false)
227    //         false, // dbvdax - MODIFIED: set to false (original value: false)
228    //         false, // dbvdb2 - MODIFIED: set to false (original value: true)
229    //         false, // dbvexasol - MODIFIED: set to false (original value: true)
230    //         false, // dbvfirebird - MODIFIED: set to false (original value: true)
231    //         false, // dbvgeneric - MODIFIED: set to false (original value: false)
232    //         false, // dbvgreenplum - MODIFIED: set to false (original value: true)
233    //         false, // dbvhana - MODIFIED: set to false (original value: true)
234    //         false,  // dbvhive - keeping as true per requirement
235    //         false, // dbvimpala - MODIFIED: set to false (original value: true)
236    //         false, // dbvinformix - MODIFIED: set to false (original value: true)
237    //         false, // dbvmdx - MODIFIED: set to false (original value: false)
238    //         false, // dbvmysql - MODIFIED: set to false (original value: true)
239    //         false, // dbvmssql - MODIFIED: set to false (original value: true)
240    //         false, // dbvnetezza - MODIFIED: set to false (original value: true)
241    //         false, // dbvodbc - MODIFIED: set to false (original value: false)
242    //         false, // dbvopenedge - MODIFIED: set to false (original value: false)
243    //         false, // dbvoracle - MODIFIED: set to false (original value: true)
244    //         false, // dbvpostgresql - MODIFIED: set to false (original value: true)
245    //         false, // dbvpresto - MODIFIED: set to false (original value: true)
246    //         false, // dbvredshift - MODIFIED: set to false (original value: true)
247    //         false, // dbvsnowflake - MODIFIED: set to false (original value: true)
248    //         false, // dbvsoql - MODIFIED: set to false (original value: false)
249    //         false,  // dbvsparksql - keeping as true per requirement
250    //         false, // dbvsybase - MODIFIED: set to false (original value: true)
251    //         false, // dbvteradata - MODIFIED: set to false (original value: true)
252    //         false, // dbvtrino - MODIFIED: set to false (original value: true)
253    //         false, // dbvvertica - MODIFIED: set to false (original value: true)
254    //         false, // dbvdatabricks - MODIFIED: set to false (original value: true)
255    //         false, // dbvgaussdb - MODIFIED: set to false (original value: true)
256    // };
257
258    public static boolean[] isAliasReferenceForbidden = {
259        false, // dbvaccess - correct
260        false, // dbvansi - correct
261        false, // dbvathena - correct
262        true,  // dbvazuresql - correct
263        true,  // dbvbigquery - correct
264        false, // dbvcouchbase - correct
265        false, // dbvdax - correct
266        true,  // dbvdb2 - correct
267        false,  // dbvexasol - CHANGE to true (Exasol disallows forward references)
268        false,  // dbvfirebird - CHANGE to true (Firebird follows standard SQL behavior)
269        false, // dbvgeneric - correct
270        true,  // dbvgreenplum - correct
271        false,  // dbvhana - CHANGE to true (SAP HANA follows standard SQL behavior)
272        true,  // dbvhive - correct
273        false,  // dbvimpala - CHANGE to true (Impala follows Hive's behavior)
274        true,  // dbvinformix - correct
275        false, // dbvmdx - correct
276        true,  // dbvmysql - correct
277        true,  // dbvmssql - correct
278        true,  // dbvnetezza - correct
279        false, // dbvodbc - correct
280        false, // dbvopenedge - correct
281        true,  // dbvoracle - correct
282        true,  // dbvpostgresql - correct
283        true,  // dbvpresto - correct
284        true,  // dbvredshift - correct
285        false,  // dbvsnowflake - CHANGE to true (Snowflake disallows column alias references)
286        false, // dbvsoql - correct
287        true,  // dbvsparksql - correct
288        true,  // dbvsybase - correct
289        false,  // dbvteradata - CHANGE to true (Teradata follows standard SQL behavior)
290        true,  // dbvtrino - correct
291        false,  // dbvvertica - CHANGE to true (Vertica disallows forward references)
292        true,  // dbvdatabricks - correct
293        true,  // dbvgaussdb - correct
294    };
295
296    public static String getStmtSeparatorChar(EDbVendor dbVendor){
297        String ret = ";";
298        switch (dbVendor){
299            case dbvoracle:
300            case dbvteradata:
301            case dbvpostgresql:
302            case dbvredshift:
303            case dbvgreenplum:
304                ret = "/";
305                break;
306            case dbvdb2:
307                ret = "@";
308                break;
309            case dbvmysql:
310                ret = "$";
311                break;
312            default:
313                break;
314        }
315        return ret;
316    }
317
318
319    /**
320     * Whether this database support schema or not?
321     *
322     * @param dbVendor
323     * @return
324     */
325    public static boolean supportSchema(EDbVendor dbVendor){
326        return (!((dbVendor == EDbVendor.dbvmysql)
327                ||(dbVendor == EDbVendor.dbvteradata)||(dbVendor == EDbVendor.dbvhive)||(dbVendor == EDbVendor.dbvimpala)
328                ));
329    }
330
331    /**
332     * Whether this database support catalog or not?
333     *
334     * @param dbVendor
335     * @return
336     */
337    public static boolean supportCatalog(EDbVendor dbVendor) {
338//        return (!((dbVendor == EDbVendor.dbvoracle)
339//        ));
340        return true;
341    }
342
343    /**
344     * used to delimit a database identifier, such as [ used in SQL Server, ` used in MySQL
345     *
346     * @param dbVendor
347     * @return
348     */
349    public static String delimitedChar(EDbVendor dbVendor){
350        String ret = "\"";
351        switch (dbVendor){
352            case dbvmssql:
353            case dbvazuresql:
354                ret = "[";
355                break;
356            case dbvathena:
357            case dbvmysql:
358            case dbvbigquery:
359            case dbvcouchbase:
360            case dbvhive:
361            case dbvimpala:
362            case dbvdatabricks:
363                ret = "`";
364                break;
365            case dbvdax:
366                ret = "'";
367                break;
368            default:
369                break;
370        }
371        return ret;
372    }
373
374    public static boolean isDelimitedIdentifier(EDbVendor dbVendor, String identifier){
375        boolean ret = false;
376        switch (dbVendor){
377            case dbvmssql:
378            case dbvazuresql:
379                ret = identifier.startsWith("[")||identifier.startsWith("\"")||identifier.startsWith("'");
380                break;
381            case dbvmysql:
382            case dbvbigquery:
383            case dbvcouchbase:
384            case dbvhive:
385            case dbvimpala:
386                ret = identifier.startsWith("`");
387                break;
388            case dbvdax:
389                ret = identifier.startsWith("'");
390                break;
391            default:
392                ret = identifier.startsWith("\"");
393                break;
394        }
395        return ret;
396    }
397    
398    public static boolean endsWithDelimitedIdentifier(EDbVendor dbVendor, String identifier){
399        boolean ret = false;
400        switch (dbVendor){
401            case dbvmssql:
402            case dbvazuresql:
403                ret = identifier.endsWith("]")||identifier.endsWith("\"");
404                break;
405            case dbvmysql:
406            case dbvbigquery:
407            case dbvcouchbase:
408            case dbvhive:
409            case dbvimpala:
410                ret = identifier.endsWith("`");
411                break;
412            case dbvdax:
413                ret = identifier.endsWith("'");
414                break;
415            default:
416                ret = identifier.endsWith("\"");
417                break;
418        }
419        return ret;
420    }
421
422    public boolean isDelimitedIdentifier(String identifier){
423        return TSQLEnv.isDelimitedIdentifier(this.getDBVendor(),identifier);
424    }
425
426
427    public boolean compareColumn(String ident1, String ident2){
428        return compareIdentifier(this.getDBVendor(),ESQLDataObjectType.dotColumn,ident1,ident2);
429    }
430
431    public boolean compareTable(String ident1, String ident2){
432        return compareIdentifier(this.getDBVendor(),ESQLDataObjectType.dotTable,ident1,ident2);
433    }
434
435    public boolean compareIdentifier(ESQLDataObjectType objectType, String ident1, String ident2){
436        switch (objectType){
437            case dotTable:
438                return compareTable(ident1,ident2);
439            case dotColumn:
440                return compareColumn(ident1,ident2);
441            default:
442                return compareIdentifier(this.getDBVendor(),objectType,ident1,ident2);
443        }
444    }
445
446    public static boolean compareColumn( EDbVendor dbVendor, TObjectName sourceColumn, TObjectName targetColumn){
447        return compareQualifiedColumn(dbVendor,sourceColumn.getColumnNameOnly(),targetColumn.getColumnNameOnly(),
448                sourceColumn.getTableString(),targetColumn.getTableString(),
449                sourceColumn.getSchemaString(),targetColumn.getSchemaString(),
450                sourceColumn.getDatabaseString(),targetColumn.getDatabaseString());
451    }
452
453    public static boolean compareTable( EDbVendor dbVendor, TObjectName sourceTable, TObjectName targetTable){
454        return compareQualifiedTable(dbVendor,
455                sourceTable.getTableString(),targetTable.getTableString(),
456                sourceTable.getSchemaString(),targetTable.getSchemaString(),
457                sourceTable.getDatabaseString(),targetTable.getDatabaseString()
458        );
459    }
460
461    public static boolean compareQualifiedTable( EDbVendor dbVendor, String sourceTable, String targetTable, String sourceSchema, String targetSchema, String sourceDatabase, String targetDatabase){
462        boolean ret = compareIdentifier(dbVendor,dotTable,sourceTable,targetTable);
463        if (!ret) return ret;
464
465        // compare schema
466        ret = compareIdentifier(dbVendor,dotSchema,sourceSchema,targetSchema);
467        if (!ret) return ret;
468
469        // compare database
470        return compareIdentifier(dbVendor,dotCatalog,sourceDatabase,targetDatabase);
471    }
472
473    public static boolean compareQualifiedColumn( EDbVendor dbVendor, String sourceColumn, String targetColumn, String sourceTable, String targetTable, String sourceSchema, String targetSchema, String sourceDatabase, String targetDatabase){
474
475        boolean ret = compareIdentifier(dbVendor,dotColumn,sourceColumn,targetColumn);
476        if (!ret) return ret;
477
478        return compareQualifiedTable(dbVendor,sourceTable,targetTable,sourceSchema,targetSchema,sourceDatabase,targetDatabase);
479    }
480
481    public static boolean compareIdentifier( EDbVendor dbVendor, ESQLDataObjectType objectType, TObjectName source, TObjectName target){
482        return compareIdentifier(dbVendor,objectType,source.toString(),target.toString());
483    }
484
485    public static boolean compareIdentifier( EDbVendor dbVendor, ESQLDataObjectType objectType, String ident1, String ident2){
486        ident1 = normalizeIdentifier(dbVendor,objectType,ident1);
487        ident2 = normalizeIdentifier(dbVendor,objectType,ident2);
488        boolean collationSensitive = false;
489        switch (objectType){
490            case dotCatalog:
491            case dotSchema:
492                collationSensitive = catalogCollationCaseSensitive[dbVendor.ordinal()];
493                break;
494            case dotOraclePackage:
495                        case dotProcedure:
496                        case dotTrigger: 
497            case dotTable:
498                collationSensitive = tableCollationCaseSensitive[dbVendor.ordinal()];
499                break;
500            case dotFunction:
501                collationSensitive = functionCollationCaseSensitive[dbVendor.ordinal()];
502                break;
503            case dotColumn:
504                collationSensitive = columnCollationCaseSensitive[dbVendor.ordinal()];
505                break;
506            case dotDblink: // oracle dblink
507                collationSensitive = false;
508                break;
509            default:
510                collationSensitive = defaultCollationCaseSensitive[dbVendor.ordinal()];
511                break;
512        }
513
514                if (collationSensitive) {
515                        return ident1.equals(ident2);
516                } else {
517                        return ident1.equalsIgnoreCase(ident2);
518                }
519    }
520
521    /**
522     * 1. remove delimited char if it's delimited/quoted identifier
523     * 2. change the case of the name in the same way as it saved to the information_schema
524     *
525     * @param dbVendor
526     * @param sqlDataObjectType
527     * @param identifier
528     * @return
529     */
530    public static String normalizeIdentifier(EDbVendor dbVendor, ESQLDataObjectType sqlDataObjectType, String identifier){
531        String ret;
532        if (identifier == null) return identifier;
533        if (identifier.length() == 0) return identifier;
534        if (TSQLEnv.isDelimitedIdentifier(dbVendor,identifier)){
535            ret = TBaseType.getTextWithoutQuoted(identifier);
536        }else {
537            switch (dbVendor){
538                case dbvdb2:
539                case dbvoracle:
540                    ret =  identifier.toUpperCase();
541                    break;
542                case dbvpostgresql:
543                case dbvgreenplum:
544                case dbvredshift:
545                    ret =  identifier.toLowerCase();
546                    break;
547                default:
548                    ret =  identifier;
549                    break;
550            }
551        }
552        return ret;
553    }
554
555    /**
556     * 比较 一个数据库对象名是否等于或者属于另一个对象
557     * 等于 就是完全相等(根据不同数据库的比较规则)
558     * 属于 表示如下情况:
559     * 1. column1 -&gt; 属于 -&gt; table1.column1
560     * 2. table1 -&gt; 属于 -&gt; db1.schema1.table1
561     * 3. `schema1.table1` -&gt; 属于 -&gt; `db1`.`schema1`.`table1`
562     * 4. `schema1.table1` -&gt; 不属于 -&gt; `db1`.`schema2`.`table1`
563     *
564     * @param sub
565     * @param whole
566     * @return
567     */
568    public static boolean matchSubObjectNameToWhole(EDbVendor dbVendor, ESQLDataObjectType sqlDataObjectType,String sub, String whole){
569        List<String> subParts = SQLUtil.parseNames(sub);
570        // `data.RETAIL_PROD_EXCEPTIONS_SOURCE` 没有被分开,需要去掉 `` 后再次拆分
571        if ((subParts.size() == 1)&&(sub.indexOf(".") != -1)){
572            subParts = SQLUtil.parseNames(TSQLEnv.normalizeIdentifier(dbVendor,sqlDataObjectType,sub));
573        }
574
575        List<String> wholeParts = SQLUtil.parseNames(whole);
576        if ((wholeParts.size() == 1)&&(whole.indexOf(".") != -1)){
577            wholeParts = SQLUtil.parseNames(TSQLEnv.normalizeIdentifier(dbVendor,sqlDataObjectType,whole));
578        }
579
580
581        if(subParts.size() >wholeParts.size()) return false;
582        int k=0;
583        for(String s:subParts){
584            subParts.set(k,TBaseType.removePrefixOrSuffixQuoteChar(normalizeIdentifier(dbVendor,sqlDataObjectType,s)));
585            k++;
586        }
587        k=0;
588        for(String s:wholeParts){
589            wholeParts.set(k, TBaseType.removePrefixOrSuffixQuoteChar(normalizeIdentifier(dbVendor,sqlDataObjectType,s)));
590            k++;
591        }
592
593        boolean ret = false;
594        int i= subParts.size() -1;
595        int j = wholeParts.size() -1;
596        while (i >= 0){
597            if ( !subParts.get(i).toUpperCase().equals(wholeParts.get(j).toUpperCase())) break;
598            if (i == 0) ret = true;
599            i--;
600            j--;
601        }
602
603        return ret;
604    }
605
606    private boolean enableGetMetadataFromDDL = true;
607
608    public void setEnableGetMetadataFromDDL(boolean enableGetMetadataFromDDL) {
609        this.enableGetMetadataFromDDL = enableGetMetadataFromDDL;
610    }
611
612    /**
613     * If this option is enabled, SQLEnv will collect table/view/function/procedure metadata
614     * from the create table/create view/create function/create procedure statement during the parse of the SQL script.
615     * <br>A TSQLEnv object instance must be passed to {@link TGSqlParser} before parsing the SQL script. And this TSQLEnv
616     * instance can be passed to another {@link TGSqlParser} object with the collected database metadata.
617     * <br>Default value is true.
618     *
619     * @return
620     */
621    public boolean isEnableGetMetadataFromDDL() {
622        return enableGetMetadataFromDDL;
623    }
624
625    /**
626     * create a SQL environment.
627     *
628     * @param dbVendor the database vendor
629     */
630    public TSQLEnv(EDbVendor dbVendor){
631        this.dbVendor = dbVendor;
632    }
633
634    private EDbVendor dbVendor;
635
636    /**
637     * the database vendor where this SQL environment is generated from.
638     *
639     * @return the database vendor
640     */
641    public EDbVendor getDBVendor() {
642        return dbVendor;
643    }
644
645    /**
646     * This method must be override in the subclass to build a SQL environment with real metadata.
647     * <br>this usually done by querying the INFORMATION_SCHEMA
648     */
649    public abstract void initSQLEnv();
650
651    /**
652     * a list of catalog/database in this SQL environment.
653     *
654     * @return a list of catalog/database
655     */
656    public List<TSQLCatalog> getCatalogList() {
657        return catalogList;
658    }
659
660    private String serverName = null; // SQL Server
661
662    private List<TSQLCatalog> catalogList = new ArrayList<TSQLCatalog>( );
663
664    /**
665     * add a catalog to the SQL environment, called internally.
666     *
667     * @param sqlCatalog catalog
668     * @return return false if a catalog with the same name already exists.
669     */
670    protected boolean doAddCatalog(TSQLCatalog sqlCatalog){
671        boolean isFound = false;
672        for(TSQLCatalog c : catalogList){
673            if ( sqlCatalog.getName().compareTo(c.getName()) == 0){
674                isFound = true;
675                break;
676            }
677        }
678        if (!isFound){
679            catalogList.add(sqlCatalog);
680        }
681        return !isFound;
682    }
683
684    private HashMap<String, TSQLSchemaObject> schemaObjectList = new HashMap<String, TSQLSchemaObject>( );
685
686    /**
687     * put a schema object into the hashmap which can be used to find a schema object in a more efficient way.
688     *
689     * @param schemaObjectName  name of schema object
690     * @param schemaObject instance of a schema object
691     * @return always return true.
692     */
693    protected boolean putSchemaObject(String schemaObjectName, TSQLSchemaObject schemaObject){
694        String newSchemaName = schemaObjectName;
695        if (schemaObject.getDataObjectType() == dotTable){
696            if (!tableCollationCaseSensitive[this.getDBVendor().ordinal()]){
697                newSchemaName = newSchemaName.toUpperCase();
698            }
699        }else {
700            if (!defaultCollationCaseSensitive[this.getDBVendor().ordinal()]){
701                newSchemaName = newSchemaName.toUpperCase();
702            }
703        }
704
705        if (schemaObject.getDataObjectType() == dotFunction){
706            newSchemaName = newSchemaName+"$function";
707        }else if (schemaObject.getDataObjectType() == dotProcedure){
708            newSchemaName = newSchemaName+"$procedure";
709        }
710
711        schemaObjectList.put(newSchemaName,schemaObject);
712        return true;
713    }
714
715    /**
716     * add a table
717     *
718     * @param qualifiedTableName, must be in syntax like: catalog.schema.table
719     * @param sqlTable, table instance
720     */
721//    public void addSQLTable(String qualifiedTableName, TSQLTable sqlTable){
722//        schemaObjectList.put(qualifiedTableName,sqlTable);
723//    }
724//
725//    public void addRoutine(String qualifiedRoutineName, TSQLRoutine sqlRoutine){
726//        schemaObjectList.put(qualifiedRoutineName,sqlRoutine);
727//    }
728
729    private String defaultCatalogName = null;
730    private String defaultSchemaName = null;
731    private String defaultServerName = null;
732
733    protected TSQLSchemaObject doSearchSchemaObject(String catalog, String schema, String table, ESQLDataObjectType objectType){
734        TSQLSchemaObject result = null;
735
736        String normalizedCurrentCatalogName = TSQLObject.normalizeIdentifier(this,ESQLDataObjectType.dotCatalog, defaultCatalogName);
737        String normalizedCurrentSchemaName = TSQLObject.normalizeIdentifier(this,ESQLDataObjectType.dotSchema, defaultSchemaName);
738
739        if ((catalog.length()>0)&&(schema.length()>0)){ // catalog.schema.table
740            result = doSearchSchemaObject(catalog+"."+schema+"."+table,objectType);
741        }else if (schema.length()>0){ //.schema.table
742            if (defaultCatalogName != null){
743                result = doSearchSchemaObject(normalizedCurrentCatalogName+"."+schema+"."+table,objectType);
744            }else{
745                for(TSQLCatalog c : catalogList){
746                    result = doSearchSchemaObject(c.name+"."+schema+"."+table,objectType);
747                    if (result != null) break;
748                }
749            }
750        }else if (catalog.length()>0){ // catalog..table
751            if (defaultSchemaName != null){
752                result = doSearchSchemaObject(catalog+"."+normalizedCurrentSchemaName+"."+table,objectType);
753            }else{
754                for(TSQLCatalog c : catalogList){
755                    if ( c.compareTo(catalog) != 0) continue;
756                    for(TSQLSchema s: c.getSchemaList()){
757                        result = doSearchSchemaObject(s.getQualifiedName()+"."+table,objectType);
758                        if (result != null) break;
759                    }
760                    if (result != null) break;
761                }
762            }
763        }else{ // ..table, search under the current default database and schema.
764            // The current default database and schema can be set by the user.
765            // if current default database and schema is not set, then search in all databases and schemas
766            for(TSQLCatalog c : catalogList){
767                if ((defaultCatalogName != null) && ( c.compareTo(defaultCatalogName) != 0)) continue;
768                for(TSQLSchema s: c.getSchemaList()){
769                    if ((defaultSchemaName != null)&&(s.compareTo(defaultSchemaName) != 0)) continue;
770                    result = doSearchSchemaObject(s.getQualifiedName()+"."+table,objectType);
771                    if (result != null) break;
772                }
773                if (result != null) break;
774            }
775        }
776
777        return result;
778    }
779
780    protected TSQLSchemaObject searchSchemaObject(TObjectName qualifiedName, ESQLDataObjectType objectType){
781
782        String catalog = TSQLObject.normalizeIdentifier(this,ESQLDataObjectType.dotCatalog, qualifiedName.getDatabaseString());
783        String schema = TSQLObject.normalizeIdentifier(this,ESQLDataObjectType.dotSchema, qualifiedName.getSchemaString());
784        String table = TSQLObject.normalizeIdentifier(this,ESQLDataObjectType.dotTable, qualifiedName.getTableString());
785
786        schema = (schema == null)?getDefaultSchemaName():schema;
787        schema = (schema == null)?"":schema;
788
789        catalog = (catalog == null)?getDefaultCatalogName():catalog;
790        catalog = (catalog == null)?"":catalog;
791
792        return doSearchSchemaObject(catalog,schema,table,objectType);
793    }
794
795    public TSQLSchemaObject searchSchemaObject(String qualifiedName, ESQLDataObjectType objectType){
796        List<String> parts = SQLUtil.parseNames(qualifiedName);
797                if (parts.size() < 3) {
798                        return null;
799                }
800
801                boolean supportCatalog = TSQLEnv.supportCatalog(dbVendor);
802                boolean supportSchema = TSQLEnv.supportSchema(dbVendor);
803
804        String catalog = TSQLObject.normalizeIdentifier(this,ESQLDataObjectType.dotCatalog, parts.get(0));
805        String schema = TSQLObject.normalizeIdentifier(this,ESQLDataObjectType.dotSchema, parts.get(1));
806        String table = TSQLObject.normalizeIdentifier(this,ESQLDataObjectType.dotTable, SQLUtil.mergeSegments(parts, 2));
807        TSQLSchemaObject object = doSearchSchemaObject(catalog,schema,table,objectType);
808
809        //如果不是同时支持database和schema,且没有找到object,交换database和schema顺序查找
810                if (!(supportCatalog && supportSchema) && object == null) {
811                        catalog = TSQLObject.normalizeIdentifier(this, ESQLDataObjectType.dotCatalog, parts.get(1));
812                        schema = TSQLObject.normalizeIdentifier(this, ESQLDataObjectType.dotSchema, parts.get(0));
813                        object = doSearchSchemaObject(catalog, schema, table, objectType);
814                }
815
816                return object;
817
818//        String normalizedCurrentCatalogName = TSQLObject.normalizeIdentifier(this,ESQLDataObjectType.dotCatalog, defaultCatalogName);
819//        String normalizedCurrentSchemaName = TSQLObject.normalizeIdentifier(this,ESQLDataObjectType.dotSchema, defaultSchemaName);
820//
821//        if ((catalog.length()>0)&&(schema.length()>0)){ // catalog.schema.table
822//            result = doSearchSchemaObject(catalog+"."+schema+"."+table,objectType);
823//        }else if (schema.length()>0){ //.schema.table
824//            if (defaultCatalogName != null){
825//                result = doSearchSchemaObject(normalizedCurrentCatalogName+"."+schema+"."+table,objectType);
826//            }else{
827//                for(TSQLCatalog c : catalogList){
828//                    result = doSearchSchemaObject(c.name+"."+schema+"."+table,objectType);
829//                    if (result != null) break;
830//                }
831//            }
832//        }else if (catalog.length()>0){ // catalog..table
833//            if (defaultSchemaName != null){
834//                result = doSearchSchemaObject(catalog+"."+normalizedCurrentSchemaName+"."+table,objectType);
835//            }else{
836//                for(TSQLCatalog c : catalogList){
837//                    if ( c.compareTo(catalog) != 0) continue;
838//                    for(TSQLSchema s: c.getSchemaList()){
839//                        result = doSearchSchemaObject(s.getQualifiedName()+"."+table,objectType);
840//                        if (result != null) break;
841//                    }
842//                    if (result != null) break;
843//                }
844//            }
845//        }else{ // ..table
846//            for(TSQLCatalog c : catalogList){
847//                if ((defaultCatalogName != null) && ( c.compareTo(defaultCatalogName) != 0)) continue;
848//                for(TSQLSchema s: c.getSchemaList()){
849//                    if ((defaultSchemaName != null)&&(s.compareTo(defaultSchemaName) != 0)) continue;
850//                    result = doSearchSchemaObject(s.getQualifiedName()+"."+table,objectType);
851//                    if (result != null) break;
852//                }
853//                if (result != null) break;
854//            }
855//        }
856//
857//        return result;
858
859    }
860    /**
861     * find a table in the SQL environment by using a qualified table name: catalogName.schemaName.tableName
862     *
863     * @param qualifiedTablename, can be catalog.schema.table,
864     *                            or .schema.table, use currentCatalogName or iterate all catalogs
865     *                            or catalog..table, use current schema name or iterate all schema under catalog
866     *                            or ..table, use currentCatalogName or iterate all catalogs, use current schema
867     *                                          or iterate all schema
868     * @return a table
869     */
870    public TSQLTable searchTable(String qualifiedTablename){
871        TSQLSchemaObject result = searchSchemaObject(qualifiedTablename,dotTable);
872
873        if (result instanceof TSQLTable){
874            return (TSQLTable)result;
875        }else return null;
876
877    }
878
879    public TSQLTable searchTable(TObjectName tableName){
880        if ((tableName.getSchemaToken() == null) && (tableName.getDatabaseToken() == null)) return searchTable(".."+tableName.getTableString());
881        if (tableName.getDatabaseToken() == null) return searchTable("."+tableName.getSchemaString()+"."+tableName.getTableString());
882        if (tableName.getSchemaToken() == null) return searchTable(tableName.getDatabaseString()+".."+tableName.getTableString());
883        return searchTable(tableName.toString());
884    }
885    /**
886     * called by {@link #searchTable(String)} method internally.
887     *
888     * @param qualifiedName table name
889     * @return return a table instance if found, otherwise, return null
890     */
891//    TSQLTable doSearchTable(String qualifiedTablename){
892//        TSQLTable result = null;
893//        TSQLSchemaObject schemaObject = schemaObjectList.get(qualifiedTablename);
894//
895//        if (schemaObject instanceof TSQLTable){
896//            result = (TSQLTable)schemaObject;
897//        }
898//        return result;
899//    }
900
901    private TSQLSchemaObject doSearchSchemaObject( String qualifiedName, ESQLDataObjectType objectType){
902        String newSchemaName = qualifiedName;
903        if (objectType == dotTable){
904            if (!tableCollationCaseSensitive[this.getDBVendor().ordinal()]){
905                newSchemaName = newSchemaName.toUpperCase();
906            }
907        }else {
908            if (!defaultCollationCaseSensitive[this.getDBVendor().ordinal()]){
909                newSchemaName = newSchemaName.toUpperCase();
910            }
911        }
912
913        if (objectType == dotFunction){
914            newSchemaName = newSchemaName+"$function";
915        }else if (objectType == dotProcedure){
916            newSchemaName = newSchemaName+"$procedure";
917        }
918        return  schemaObjectList.get(newSchemaName);
919    }
920
921    /**
922     * the current active catalog/database in the SQL environment.
923     * If search a table in syntax like this:  .schemaName.tableName and this current catalog name is not null,
924     * then, search the table in this syntax: currentCatalogName.schemaName.tableName.
925     * If the current catalog name is null, search all catalogs in the catalog list.
926     *
927     * @return the name of the current active catalog/database
928     */
929    public String getDefaultCatalogName() {
930        return defaultCatalogName;
931    }
932
933    /**
934     * the current schema name in the SQL environment.
935     * <br>
936     * If search a table in syntax like this:  catalogname..tableName and this current schema name is not null,
937     * then, search the table in this syntax: catalogName.currentSchemaName.tableName.
938     * If the current schema name is null, search all schemas under catalogName
939     *
940     * @return the default schema name
941     */
942    public String getDefaultSchemaName() {
943        return defaultSchemaName;
944    }
945
946    public void setDefaultCatalogName(String defaultCatalogName) {
947        this.defaultCatalogName = defaultCatalogName;
948    }
949
950    public void setDefaultSchemaName(String defaultSchemaName) {
951        this.defaultSchemaName = defaultSchemaName;
952    }
953
954    public String getDefaultServerName() {
955        return defaultServerName;
956    }
957
958    public void setDefaultServerName(String defaultServerName) {
959        this.defaultServerName = defaultServerName;
960    }
961
962
963
964    /**
965     * create a new catalog/database in the SQL environment.
966     *
967     * @param catalogName catalog name
968     * @return instance of the created catalog
969     */
970    public TSQLCatalog createSQLCatalog(String catalogName){
971        return getSQLCatalog(catalogName,true);
972    }
973
974    /**
975     * get a catalog from the SQL environment if already exists, otherwise, create a new catalog.
976     *
977     * @param catalogName catalog name
978     * @param createIfNotExist if this value is true, then create a new catalog if it's not exists
979     * @return a catalog instance
980     */
981    public TSQLCatalog getSQLCatalog(String catalogName, boolean createIfNotExist){
982        TSQLCatalog result = searchCatalog(catalogName);
983
984        if ((createIfNotExist)&&(result == null)){
985            result = new TSQLCatalog(this,catalogName);
986        }
987        return result;
988    }
989
990    /**
991     * search catalog in the catalog list, return null if not found.
992     *
993     * @param catalogName catalog name
994     * @return null if not found.
995     */
996    public TSQLCatalog searchCatalog(String catalogName){
997        TSQLCatalog result = null;
998        for(TSQLCatalog c : catalogList){
999            if (c.compareTo(catalogName)==0){
1000                result = c;
1001                break;
1002            }
1003        }
1004        return result;
1005    }
1006
1007    /**
1008     * create a new schema and add to the catalog
1009     *
1010     * @param qualifiedSchemaName must be a qualified name like: catalog.schema. Otherwise, a null exception will be raised.
1011     * @return a new schema instance
1012     */
1013    public TSQLSchema createSQLSchema(String qualifiedSchemaName){
1014        return  getSQLSchema(qualifiedSchemaName,true);
1015    }
1016
1017    /**
1018     * get a schema from the specified catalog, if not exists, create a new schema in the catalog.
1019     *
1020     * @param qualifiedSchemaName must be a qualified name like: catalog.schema. Otherwise, a null exception will be raised.
1021     * @param createIfNotExist  if this value is true, then create a new schema if it's not exists
1022     * @return a schema instance
1023     */
1024    public TSQLSchema getSQLSchema(String qualifiedSchemaName, boolean createIfNotExist){
1025        TSQLSchema result = null;
1026        String[] parts = SQLUtil.parseNames(qualifiedSchemaName).toArray(new String[0]);
1027        String catalogName = parts[0];
1028        String schemaName = parts[1];
1029        TSQLCatalog catalog = getSQLCatalog(catalogName,createIfNotExist);
1030        return  catalog.getSchema(schemaName,createIfNotExist);
1031    }
1032
1033
1034    /**
1035     *
1036     * @param qualifiedTablename 需要完整的tablename,例如 catalog.schema.table, 如果仅传入 table name,
1037     *                           需要利用 default catalog, default schema 拼接完整的名称: catalog.schema.table
1038     * @param columnNameOnly
1039     * @return
1040     */
1041    public  ArrayList<String> getColumnsInTable(String qualifiedTablename,boolean columnNameOnly){
1042
1043        //TSQLTable tsqlTable = searchTable(getAFullQualifiedSchemaObjectName(qualifiedTablename));
1044        TSQLTable tsqlTable = searchTable(qualifiedTablename);
1045        if (tsqlTable == null) return null;
1046        //return tsqlTable.searchColumn(columnName);
1047        return  tsqlTable.getColumns(columnNameOnly);
1048    }
1049
1050    public boolean columnInTable(String qualifiedTablename, String columnName){
1051        TSQLTable tsqlTable = searchTable(qualifiedTablename);
1052        if (tsqlTable == null) return false;
1053        return tsqlTable.searchColumn(columnName);
1054    }
1055
1056    public TSQLColumn getColumnInTable(String qualifiedTablename, String columnName){
1057        StringBuilder builder = new StringBuilder();
1058        String db = (getDatabaseName(qualifiedTablename) == null)?getDefaultCatalogName():getDatabaseName(qualifiedTablename);
1059        if((db == null) || (db.length() == 0)) {
1060                builder.append(DEFAULT_DB_NAME).append(".");
1061        }
1062        
1063        String schema = (getSchemaName(qualifiedTablename) == null)?getDefaultSchemaName():getSchemaName(qualifiedTablename);
1064        if ((schema == null)||(schema.length() == 0)) {
1065                builder.append(DEFAULT_SCHEMA_NAME).append(".");
1066        }
1067        
1068        builder.append(qualifiedTablename);
1069        
1070        TSQLTable tsqlTable = searchTable(builder.toString());
1071        if (tsqlTable == null) return null;
1072        return tsqlTable.getColumn(columnName);
1073    }
1074
1075//    String[] getCatalogSchemaNameWithDefault(String qualifiedObjectName){
1076//        String[] catalogSchemaName = new String[2];
1077//
1078//        if (qualifiedObjectName.startsWith("`") && qualifiedObjectName.endsWith("`")){
1079//            qualifiedObjectName = qualifiedObjectName.substring(1,qualifiedObjectName.length()-1);
1080//        }
1081//
1082//        String db = (getDatabaseName(qualifiedObjectName) == null)?getDefaultCatalogName():getDatabaseName(qualifiedObjectName);
1083//        if((db == null) || (db.length() == 0)) db = DEFAULT_DB_NAME;
1084//        String schema = (getSchemaName(qualifiedObjectName) == null)?getDefaultSchemaName():getSchemaName(qualifiedObjectName);
1085//        if ((schema == null)||(schema.length() == 0)) schema = DEFAULT_SCHEMA_NAME;
1086//
1087//        catalogSchemaName[0] = db;
1088//        catalogSchemaName[1] = schema;
1089//
1090//        return  catalogSchemaName;
1091//    }
1092    public TSQLSchemaObject doAddSchemaObject(String qualifiedObjectName,ESQLDataObjectType objectType){
1093
1094        if (qualifiedObjectName.startsWith("`") && qualifiedObjectName.endsWith("`")){
1095            qualifiedObjectName = SQLUtil.trimColumnStringQuote(qualifiedObjectName);
1096        }
1097
1098        String db = (getDatabaseName(qualifiedObjectName) == null)?getDefaultCatalogName():getDatabaseName(qualifiedObjectName);
1099        if((db == null) || (db.length() == 0)) db = DEFAULT_DB_NAME;
1100        String schema = (getSchemaName(qualifiedObjectName) == null)?getDefaultSchemaName():getSchemaName(qualifiedObjectName);
1101        if ((schema == null)||(schema.length() == 0)) schema = DEFAULT_SCHEMA_NAME;
1102
1103        // getCatalogSchemaNameWithDefault 这个函数有问题,为导致测试用例失败
1104        //        String[] catalogSchemaName = getCatalogSchemaNameWithDefault(qualifiedObjectName);
1105//        String db = catalogSchemaName[0];
1106//        String schema = catalogSchemaName[1];
1107
1108        TSQLCatalog sqlCatalog = createSQLCatalog(db);
1109        TSQLSchema sqlSchema = sqlCatalog.createSchema(schema);
1110        return sqlSchema.createSchemaObject(getObjectName(qualifiedObjectName),objectType);
1111    }
1112
1113    public TSQLSchemaObject doAddSchemaObject(TObjectName qualifiedObjectName,ESQLDataObjectType objectType){
1114        String db = (getDatabaseName(qualifiedObjectName) == null)?getDefaultCatalogName():getDatabaseName(qualifiedObjectName);
1115        if((db == null) || (db.length() == 0)) db = DEFAULT_DB_NAME;
1116        String schema = (getSchemaName(qualifiedObjectName) == null)?getDefaultSchemaName():getSchemaName(qualifiedObjectName);
1117        if ((schema == null)||(schema.length() == 0)) schema = DEFAULT_SCHEMA_NAME;
1118        TSQLCatalog sqlCatalog = createSQLCatalog(db);
1119        TSQLSchema sqlSchema = sqlCatalog.createSchema(schema);
1120        return sqlSchema.createSchemaObject(getObjectName(qualifiedObjectName),objectType);
1121    }
1122
1123    /**
1124     * Add a function to SQLEnv, if a function with the same already exists, just return the existing one.
1125     *
1126     * @param qualifiedFunctionName
1127     * @return function
1128     */
1129    public TSQLFunction addFunction(String qualifiedFunctionName, boolean fromDDL){
1130        if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return  null;
1131        return (TSQLFunction)doAddSchemaObject(qualifiedFunctionName,ESQLDataObjectType.dotFunction);
1132    }
1133
1134    public TSQLFunction addFunction(TObjectName qualifiedFunctionName, boolean fromDDL){
1135        if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return  null;
1136        return (TSQLFunction)doAddSchemaObject(qualifiedFunctionName,ESQLDataObjectType.dotFunction);
1137    }
1138
1139    public TSQLProcedure addOraclePackage(String qualifiedProcedureName, boolean fromDDL){
1140        if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return  null;
1141        return (TSQLProcedure)doAddSchemaObject(qualifiedProcedureName, ESQLDataObjectType.dotOraclePackage);
1142    }
1143
1144    public TSQLProcedure addProcedure(String qualifiedProcedureName, boolean fromDDL){
1145        if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return  null;
1146        return (TSQLProcedure)doAddSchemaObject(qualifiedProcedureName,ESQLDataObjectType.dotProcedure);
1147    }
1148
1149    public TSQLRoutine addSQLRoutine(String qualifiedProcedureName, boolean fromDDL, ESQLDataObjectType type){
1150        if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return  null;
1151        return (TSQLRoutine)doAddSchemaObject(qualifiedProcedureName,type);
1152    }
1153
1154    public TSQLTrigger addTrigger(String qualifiedTriggerName, boolean fromDDL){
1155        if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return  null;
1156        return (TSQLTrigger)doAddSchemaObject(qualifiedTriggerName,ESQLDataObjectType.dotTrigger);
1157    }
1158
1159    /**
1160     * Add a new table to the SQLEnv. If the table with the same name already exists in the SQLEnv,
1161     * the existing table will be returned.
1162     * <br>dbName.schemaName.tablename. If dbName is not specified, {@link #getDefaultCatalogName()} will be used to put this table in.
1163     * If schemaName is not specified, {@link #getDefaultSchemaName()} will be used to put this table in.
1164     * <br>If the specified database and schema are not already exists, a new database/schema will be generated automatically.
1165     *
1166     * @param qualifiedTableName qualified table name
1167     * @param fromDDL is this table generated from a create table statement
1168     *
1169     * @return SQL Table
1170     */
1171    public TSQLTable addTable(String qualifiedTableName, boolean fromDDL){
1172        if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return  null;
1173        return (TSQLTable)doAddSchemaObject(qualifiedTableName,ESQLDataObjectType.dotTable);
1174    }
1175
1176    public TSQLTable addView(String qualifiedViewName, boolean fromDDL){
1177        if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return  null;
1178        TSQLTable tsqlTable = (TSQLTable)doAddSchemaObject(qualifiedViewName,ESQLDataObjectType.dotTable);
1179        tsqlTable.setView(true);
1180        return tsqlTable;
1181    }
1182
1183    public static String getObjectName(TObjectName schemaObjectName){
1184        if (schemaObjectName.getObjectString().length() == 0) return null;
1185        else
1186          return schemaObjectName.getObjectString();
1187    }
1188
1189    public static String getObjectName(String schemaObjectName){
1190        String[] names = schemaObjectName.split("[.]");
1191        return names[names.length-1];
1192    }
1193
1194    public static String getDatabaseName(TObjectName schemaObjectName){
1195        if (schemaObjectName.getDatabaseString().length() == 0)
1196            return null;
1197        else
1198           return schemaObjectName.getDatabaseString();
1199    }
1200
1201    public static String getDatabaseName(String schemaObjectName){
1202        String[] names = schemaObjectName.split("[.]");
1203        if (names.length == 3){
1204            return names[0];
1205        }else if (names.length == 4){
1206            return names[1];
1207        }else{
1208            return null;
1209        }
1210    }
1211
1212    public static String getSchemaName(TObjectName schemaObjectName){
1213        if (schemaObjectName.getSchemaString().length() == 0) return null;
1214        else
1215          return schemaObjectName.getSchemaString();
1216    }
1217
1218    public static String getSchemaName(String schemaObjectName){
1219        String[] names = schemaObjectName.split("[.]");
1220        if (names.length == 2){
1221            return names[0];
1222        }else if (names.length == 3){
1223            return names[1];
1224        }else if (names.length == 4){
1225            return names[2];
1226        }else{
1227            return null;
1228        }
1229    }
1230
1231    public TSQLFunction searchFunction(TObjectName qualifiedTablename) {
1232        TSQLSchemaObject result = searchSchemaObject(qualifiedTablename,dotFunction);
1233
1234        if (result instanceof TSQLFunction) {
1235            return (TSQLFunction) result;
1236        } else return null;
1237    }
1238
1239    public TSQLFunction searchFunction(String qualifiedTablename) {
1240        TSQLSchemaObject result = searchSchemaObject( getAFullQualifiedSchemaObjectName(qualifiedTablename),dotFunction);
1241
1242        if (result instanceof TSQLFunction) {
1243            return (TSQLFunction) result;
1244        } else return null;
1245    }
1246
1247    /**
1248     * If the input name is fully qualified with db and schema, just return it without any modification.
1249     * If the schema name is missed, use {@link #getDefaultSchemaName()} instead
1250     * If the database name is missed, use {@link #getDefaultCatalogName()} instead
1251     *
1252     * some sample result:
1253     * <br>
1254     * db.schema.table
1255     * .schema.table,  {@link #getDefaultCatalogName()} is null
1256     * ..table, both {@link #getDefaultCatalogName()} and {@link #getDefaultSchemaName()} are null.
1257     *
1258     * @param schemaObjectName
1259     * @return
1260     */
1261    public String getAFullQualifiedSchemaObjectName(String schemaObjectName){
1262        if (schemaObjectName.split("[.]").length == 3) return schemaObjectName;
1263        String schema = (getDefaultSchemaName() == null)?"":getDefaultSchemaName();
1264        String db = (getDefaultCatalogName() == null)?"":getDefaultCatalogName();
1265
1266        String[] names = schemaObjectName.split("[.]");
1267        if (names.length == 1){ // no prefixed schema, db
1268            return db+"."+schema+"."+schemaObjectName;
1269        }else if (names.length == 2){ // prefix with schema, no database
1270            return db+"."+names[0]+"."+names[1];
1271        }else {
1272            return schemaObjectName;
1273        }
1274    }
1275
1276    public static final String DEFAULT_SERVER_NAME = "DEFAULT_SERVER";
1277    public static final String DEFAULT_DB_NAME = "DEFAULT";
1278    public static final String DEFAULT_SCHEMA_NAME = "DEFAULT";
1279
1280    public int getNumberOfTables(){
1281        int numOfTables = 0;
1282        for(int i=0;i<getCatalogList().size();i++){
1283            TSQLCatalog tsqlCatalog = getCatalogList().get(i);
1284            for(TSQLSchema tsqlSchema: tsqlCatalog.getSchemaList()){
1285                for(TSQLSchemaObject schemaObject: tsqlSchema.getSchemaObjectList()){
1286                    switch (schemaObject.getDataObjectType()){
1287                        case dotTable:
1288                            numOfTables++;
1289                            break;
1290                        case dotProcedure:
1291                            break;
1292                        case dotFunction:
1293                            break;
1294                        case dotOraclePackage:
1295                            break;
1296                    }
1297                } //schema object list
1298            } // schema list
1299        } //catalog list
1300        return numOfTables;
1301    }
1302
1303    public String toString(){
1304        String lcResult = "";
1305        StringBuilder tables = new StringBuilder();
1306        StringBuilder views = new StringBuilder();
1307        StringBuilder functions = new StringBuilder();
1308        StringBuilder oraclePackages = new StringBuilder();
1309        StringBuilder procedures = new StringBuilder();
1310        for(int i=0;i<getCatalogList().size();i++){
1311            TSQLCatalog tsqlCatalog = getCatalogList().get(i);
1312            lcResult = lcResult+"\ndatabase:"+tsqlCatalog.getName();
1313            for(TSQLSchema tsqlSchema: tsqlCatalog.getSchemaList()){
1314                lcResult = lcResult+"\n\t"+"schema:"+tsqlSchema.getName();
1315                for(TSQLSchemaObject schemaObject: tsqlSchema.getSchemaObjectList()){
1316                    switch (schemaObject.getDataObjectType()){
1317                        case dotTable:
1318                            TSQLTable tsqlTable = (TSQLTable)schemaObject;
1319                            if (tsqlTable.isView()){
1320                                views.append("\n\t\t\t"+schemaObject.getName());
1321                                for(TSQLColumn column: tsqlTable.getColumnList()){
1322                                    views.append("\n\t\t\t\t"+column.getName());
1323
1324                                }
1325                            }else{
1326                                tables.append("\n\t\t\t"+schemaObject.getName());
1327                                for(TSQLColumn column: tsqlTable.getColumnList()){
1328                                    tables.append("\n\t\t\t\t"+column.getName());
1329                                    if (column.getColumnDataType() != null){
1330                                        tables.append(",\t"+column.getColumnDataType().toString());
1331                                        TTypeName subType;
1332                                        switch (column.getColumnDataType().getDataType()){
1333                                            case array_t:
1334                                                subType = column.getColumnDataType().getTypeOfList();
1335
1336                                                if (subType.getDataType() == EDataType.struct_t){
1337
1338                                                    for(int k=0;k<subType.getColumnDefList().size();k++){
1339                                                        //System.out.println(subType.getColumnDefList().getColumn(k).getColumnName());
1340                                                        //System.out.println(subType.getColumnDefList().getColumn(k).getDatatype());
1341                                                        tables.append("\n\t\t\t\t\t\t"+ subType.getColumnDefList().getColumn(k).getColumnName().toString()
1342                                                                +",\t"+ subType.getColumnDefList().getColumn(k).getDatatype().toString());
1343                                                    }
1344                                                }
1345                                                break;
1346                                            case struct_t:
1347                                                subType = column.getColumnDataType();
1348                                                for(int k=0;k<subType.getColumnDefList().size();k++){
1349                                                    tables.append("\n\t\t\t\t\t\t"+ subType.getColumnDefList().getColumn(k).getColumnName().toString()
1350                                                            +",\t"+ subType.getColumnDefList().getColumn(k).getDatatype().toString());
1351                                                }
1352                                                break;
1353                                        }
1354                                    }
1355                                }
1356                            }
1357
1358                            break;
1359                        case dotProcedure:
1360                            procedures.append("\n\t\t\t"+schemaObject.getName());
1361                            break;
1362                        case dotFunction:
1363                            functions.append("\n\t\t\t"+schemaObject.toString());
1364                            //TSQLFunction f = (TSQLFunction) schemaObject;
1365
1366                            break;
1367                        case dotOraclePackage:
1368                            oraclePackages.append("\n\t\t\t"+schemaObject.getName());
1369                            break;
1370                    }
1371                } //schema object list
1372                lcResult = lcResult+"\n\t\t"+"tables:"+tables.toString();
1373                lcResult = lcResult+"\n\t\t"+"views:"+views.toString();
1374                if(oraclePackages.length()>0) {
1375                    lcResult = lcResult + "\n\t\t" + "oracle package:" + oraclePackages.toString();
1376                }
1377                lcResult = lcResult+"\n\t\t"+"procedure:"+procedures.toString();
1378                lcResult = lcResult+"\n\t\t"+"function:"+functions.toString();
1379                tables.setLength(0);
1380                views.setLength(0);
1381                procedures.setLength(0);
1382                functions.setLength(0);
1383            } // schema list
1384        } //catalog list
1385        return lcResult;
1386    }
1387
1388    public String getProcedureParameterValue(String procedureName, int paramPos){
1389        return "";
1390    }
1391    public void getVariableValue(String variableName, String variableValue){}
1392
1393    private static boolean usedBySqlflow = false;
1394
1395    public static boolean isUsedBySqlflow() {
1396        return usedBySqlflow;
1397    }
1398}