EMMA Coverage Report (generated Wed Jun 28 22:15:27 PDT 2006)
[all classes][org.apache.derby.tools]

COVERAGE SUMMARY FOR SOURCE FILE [dblook.java]

nameclass, %method, %block, %line, %
dblook.java100% (1/1)96%  (26/27)89%  (1216/1367)84%  (274.9/326)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class dblook100% (1/1)96%  (26/27)89%  (1216/1367)84%  (274.9/326)
<static initializer> 100% (1/1)100% (54/54)100% (2/2)
addQuotes (String): String 100% (1/1)100% (15/15)100% (3/3)
dblook (String []): void 100% (1/1)97%  (31/32)92%  (12/13)
expandDoubleQuotes (String): String 100% (1/1)100% (57/57)100% (11/11)
extractDBNameFromUrl (String): String 100% (1/1)93%  (106/114)91%  (22.8/25)
extractTableNamesFromList (String [], int): int 100% (1/1)96%  (70/73)83%  (10/12)
getColNameFromNumber (String, int): String 100% (1/1)55%  (24/44)70%  (7/10)
getColumnListFromDescription (String, String): String 100% (1/1)81%  (82/101)94%  (19.7/21)
go (): void 100% (1/1)88%  (81/92)86%  (27.5/32)
initState (): void 100% (1/1)100% (21/21)100% (11/11)
isExcludedTable (String): boolean 100% (1/1)95%  (35/37)88%  (7/8)
isIgnorableSchema (String): boolean 100% (1/1)100% (35/35)100% (8/8)
loadDriver (): boolean 100% (1/1)85%  (29/34)77%  (10/13)
loadParam (String [], int): int 100% (1/1)78%  (129/165)63%  (27/43)
lookupMessage (String): String 100% (1/1)100% (4/4)100% (1/1)
lookupMessage (String, String []): String 100% (1/1)67%  (22/33)78%  (7/9)
lookupSchemaId (String): String 100% (1/1)100% (5/5)100% (1/1)
lookupTableId (String): String 100% (1/1)100% (5/5)100% (1/1)
main (String []): void 0%   (0/1)0%   (0/10)0%   (0/5)
parseArgs (String []): boolean 100% (1/1)94%  (67/71)88%  (14/16)
partOfWord (String, int, int, int): boolean 100% (1/1)96%  (49/51)99%  (8.9/9)
prepForDump (): void 100% (1/1)100% (71/71)100% (13/13)
removeNewlines (String): String 100% (1/1)71%  (32/45)62%  (8/13)
showVariables (): void 100% (1/1)100% (46/46)100% (14/14)
stringContainsTargetTable (String): boolean 100% (1/1)96%  (98/102)90%  (19/21)
stripQuotes (String): String 100% (1/1)94%  (30/32)86%  (6/7)
writeVerboseOutput (String, String): void 100% (1/1)100% (18/18)100% (4/4)

1/*
2 
3   Derby - Class org.apache.derby.tools.dblook
4 
5   Copyright 2003, 2004 The Apache Software Foundation or its licensors, as applicable.
6 
7   Licensed under the Apache License, Version 2.0 (the "License");
8   you may not use this file except in compliance with the License.
9   You may obtain a copy of the License at
10 
11      http://www.apache.org/licenses/LICENSE-2.0
12 
13   Unless required by applicable law or agreed to in writing, software
14   distributed under the License is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18 
19 */
20 
21package org.apache.derby.tools;
22 
23import java.io.BufferedReader;
24import java.io.StringReader;
25 
26import java.sql.DriverManager;
27import java.sql.ResultSet;
28import java.sql.Connection;
29import java.sql.Statement;
30import java.sql.PreparedStatement;
31import java.sql.SQLException;
32import java.sql.SQLWarning;
33import java.sql.Timestamp;
34 
35import java.util.HashMap;
36import java.util.StringTokenizer;
37import java.util.ArrayList;
38 
39import org.apache.derby.iapi.tools.i18n.LocalizedResource;
40 
41import org.apache.derby.impl.tools.dblook.DB_Check;
42import org.apache.derby.impl.tools.dblook.DB_Index;
43import org.apache.derby.impl.tools.dblook.DB_Jar;
44import org.apache.derby.impl.tools.dblook.DB_Key;
45import org.apache.derby.impl.tools.dblook.DB_Table;
46import org.apache.derby.impl.tools.dblook.DB_Schema;
47import org.apache.derby.impl.tools.dblook.DB_Alias;
48import org.apache.derby.impl.tools.dblook.DB_Trigger;
49import org.apache.derby.impl.tools.dblook.DB_View;
50import org.apache.derby.impl.tools.dblook.DB_GrantRevoke;
51import org.apache.derby.impl.tools.dblook.Logs;
52 
53public final class dblook {
54 
55        // DB2 enforces a maximum of 30 tables to be specified as part of
56        // the table list.
57        private static final int DB2_MAX_NUMBER_OF_TABLES = 30;
58 
59        private Connection conn;
60        private static PreparedStatement getColNameFromNumberQuery;
61 
62        // Mappings from id to name for schemas and tables (for ease
63        // of reference).
64        private static HashMap schemaMap;
65        private static HashMap tableIdToNameMap;
66 
67        // Command-line Parameters.
68        private static String sourceDBUrl;
69        private static String ddlFileName;
70        private static String stmtDelimiter;
71        private static boolean appendLogs;
72        private static ArrayList tableList;
73        private static String schemaParam;
74        private static String targetSchema;
75        private static boolean skipViews;
76        private static boolean verbose;
77        private static String sourceDBName;
78 
79        private static String lookLogName = "dblook.log";
80 
81        private static LocalizedResource langUtil;
82 
83        private static boolean sqlAuthorization;
84 
85        /* ************************************************
86         * main:
87         * Initialize program state by creating a dblook object,
88         * and then start the DDL generation by calling "go".
89         * ****/
90 
91        public static void main(String[] args) {
92 
93                try {
94                        new dblook(args);
95                } catch (Exception e) {
96                // All "normal" errors are logged and printed to
97                // console according to command line arguments,
98                // so if we get here, something unexpected must
99                // have happened; print to error stream.
100                        e.printStackTrace();
101                }
102 
103        }
104 
105        /* ************************************************
106         * Constructor:
107         * Parse the command line, initialize logs, echo program variables,
108         * and load the Derby driver.
109         * @param args Array of dblook command-line arguments.
110         * ****/
111 
112        public dblook(String[] args) throws Exception {
113 
114        // Adjust the application in accordance with derby.ui.locale
115                // and derby.ui.codeset
116                langUtil = LocalizedResource.getInstance();
117 
118                // Initialize class variables.
119                initState();
120 
121                // Parse the command line.
122                if (!parseArgs(args)) {
123                        System.out.println(lookupMessage("DBLOOK_Usage"));
124                        return;
125                }
126 
127                showVariables();
128 
129                if (!loadDriver()) {
130                // Failed when loading the driver.  We already logged
131                // the exception, so just return.
132                        return;
133                }
134 
135                schemaMap = new HashMap();
136                tableIdToNameMap = new HashMap();
137 
138                // Now run the utility.
139                go();
140 
141        }
142 
143        /* ************************************************
144         * initState:
145         * Initialize class variables.
146         ****/
147 
148        private void initState() {
149 
150                sourceDBUrl = null;
151                ddlFileName = null;
152                stmtDelimiter = null;
153                appendLogs = false;
154                tableList = null;
155                targetSchema = null;
156                schemaParam = null;
157                skipViews = false;
158                verbose= false;
159                sourceDBName = null;
160                return;
161 
162        }
163 
164        /* ************************************************
165         * parseArgs:
166         * Parse the command-line arguments.
167         * @param args args[0] is the url for the source database.
168         * @return true if all parameters were loaded and the output
169         *  files were successfully created; false otherwise.
170         ****/
171 
172        private boolean parseArgs(String[] args) {
173 
174                if (args.length < 2)
175                // must have minimum of 2 args: "-d" and "<dbUrl>".
176                        return false;
177 
178                int st = 0;
179                for (int i = 0; i < args.length; i++) {
180                        st = loadParam(args, i);
181                        if (st == -1)
182                                return false;
183                        i = st;
184                }
185 
186                if (sourceDBUrl == null) {
187                // must have at least a database url.
188                        return false;        
189                }
190 
191                // At this point, all parameters should have been read into
192                // their respective class variables.  Use those
193                // variables for some further processing.
194 
195                // Setup logs.
196                boolean okay = Logs.initLogs(lookLogName, ddlFileName, appendLogs,
197                         verbose, (stmtDelimiter == null ? ";" : stmtDelimiter));
198 
199                // Get database name.
200                sourceDBName = extractDBNameFromUrl(sourceDBUrl);
201 
202                // Set up schema restriction.
203                if ((schemaParam != null) && (schemaParam.length() > 0) &&
204                        (schemaParam.charAt(0) != '"'))
205                // not quoted, so upper case, then add quotes.
206                {
207                        targetSchema = addQuotes(expandDoubleQuotes(
208                                schemaParam.toUpperCase(java.util.Locale.ENGLISH)));
209                }
210                else
211                        targetSchema = addQuotes(expandDoubleQuotes(stripQuotes(schemaParam)));
212                return okay;
213 
214        }
215 
216        /* ************************************************
217         * loadParam:
218         * Read in a flag and its corresponding values from
219         * list of command line arguments, starting at
220         * the start'th argument.
221         * @return The position of the argument that was
222         *  most recently processed.
223         ****/
224 
225        private int loadParam(String [] args, int start) {
226 
227                if ((args[start].length() == 0) || args[start].charAt(0) != '-')
228                // starting argument should be a flag; if it's
229                // not, ignore it.
230                        return start;
231 
232                boolean haveVal = (args.length > start + 1);
233                switch (args[start].charAt(1)) {
234 
235                        case 'd':
236                                if (!haveVal)
237                                        return -1;
238                                if (args[start].length() == 2) {
239                                        sourceDBUrl = stripQuotes(args[++start]);
240                                        return start;
241                                }
242                                return -1;
243 
244                        case 'z':
245                                if (!haveVal)
246                                        return -1;
247                                if (args[start].length() == 2) {
248                                        schemaParam = args[++start];
249                                        return start;
250                                }
251                                return -1;
252 
253                        case 't':
254                                if (!haveVal)
255                                        return -1;
256                                if (args[start].equals("-td")) {
257                                        stmtDelimiter = args[++start];
258                                        return start;
259                                }
260                                else if (args[start].equals("-t"))
261                                // list of tables.
262                                        return extractTableNamesFromList(args, start+1);
263                                return -1;
264 
265                        case 'o':
266                                if (!haveVal)
267                                        return -1;
268                                if ((args[start].length() == 2) && (args[start+1].length() > 0)) {
269                                        ddlFileName = args[++start];
270                                        return start;
271                                }
272                                return -1;
273 
274                        case 'a':
275                                if (args[start].equals("-append")) {
276                                        appendLogs = true;
277                                        return start;
278                                }
279                                return -1;
280 
281                        case 'n':
282                                if (args[start].equals("-noview")) {
283                                        skipViews = true;
284                                        return start;
285                                }
286                                return -1;
287 
288                        case 'v':
289                                if (args[start].equals("-verbose")) {
290                                        verbose = true;
291                                        return start;
292                                }
293                                return -1;
294 
295                        default:
296                                return -1;
297 
298                }
299 
300        }
301 
302        /* ************************************************
303         * loadDriver:
304         * Load derby driver.
305         * @param precondition sourceDBUrl has been loaded.
306         * @return false if anything goes wrong; true otherwise.
307         ****/
308 
309        private boolean loadDriver() {
310 
311                String derbyDriver = System.getProperty("driver");
312                if (derbyDriver == null) {
313                        if (sourceDBUrl.indexOf(":net://") != -1)
314                                derbyDriver = "com.ibm.db2.jcc.DB2Driver";
315                        else if (sourceDBUrl.startsWith("jdbc:derby://"))
316                           derbyDriver = "org.apache.derby.jdbc.ClientDriver";
317                        else
318                                derbyDriver = "org.apache.derby.jdbc.EmbeddedDriver";
319            }
320 
321                try {
322                        Class.forName(derbyDriver).newInstance();
323            }
324                catch (Exception e)
325                {
326                        Logs.debug(e);
327                        return false;
328                }
329 
330                return true;
331        }
332 
333        /* ************************************************
334         * extractDBNameFromUrl:
335         * Given a database url, parse out the actual name
336         * of the database.  This is required for creation
337         * the DB2JJARS directory (the database name is part
338         * of the path to the jar).
339         * @param dbUrl The database url from which to extract the
340         *  the database name.
341         * @return the name of the database (including its
342         *  path, if provided) that is referenced by the url.
343         ****/
344 
345        private String extractDBNameFromUrl(String dbUrl) {
346 
347                if (dbUrl == null)
348                // shouldn't happen; ignore it here, as an error
349                // will be thrown we try to connect.
350                        return "";
351 
352                int start = dbUrl.indexOf("jdbc:derby:");
353                if (start == -1)
354                // not a valid url; just ignore it (an error
355                // will be thrown when we try to connect).
356                        return "";
357 
358                start = dbUrl.indexOf("://");
359                if (start == -1)
360                // standard url (jdbc:derby:<dbname>).  Database
361                // name starts right after "derby:".  The "6" in
362                // the following line is the length of "derby:".
363                        start = dbUrl.indexOf("derby:") + 6;
364                else
365                // Network Server url.  Database name starts right
366                // after next slash (":net://hostname:port/<dbname>).
367                // The "3" in the following line is the length of
368                // "://".
369                        start = dbUrl.indexOf("/", start+3) + 1;
370 
371                int stop = -1;
372                if (dbUrl.charAt(start) == '"') {
373                // database name is quoted; end of the name is the
374                // closing quote.
375                        start++;
376                        stop = dbUrl.indexOf("\"", start);
377                }
378                else {
379                // Database name ends with the start of a list of connection        
380                // attributes.  This list can begin with either a colon
381                // or a semi-colon.
382                        stop = dbUrl.indexOf(":", start);
383                        if (stop != -1) {
384                                if ((dbUrl.charAt(stop+1) == '/') ||
385                                                (dbUrl.charAt(stop+1) == '\\'))
386                                // then this colon is part of the path (ex. "C:"),
387                                // so ignore it.
388                                        stop = dbUrl.indexOf(":", stop+2);
389                        }
390                        int stop2 = dbUrl.length();
391                        if (stop == -1)
392                        // no colons; see if we can find a semi-colon.
393                                stop = dbUrl.indexOf(";", start);
394                        else
395                                stop2 = dbUrl.indexOf(";", start);
396                        stop = (stop <= stop2 ? stop : stop2);
397                }
398 
399                if (stop == -1)
400                // we have a url that ends with database name (no
401                // other attributes appended).
402                        stop = dbUrl.length();
403 
404                return dbUrl.substring(start, stop);
405 
406        }
407 
408        /* ************************************************
409         * extractTableNamesFromList:
410         * Given an array of command line arguments containing
411         * a list of table names beginning at start'th position,
412         * read the list of table names and store them as
413         * our target table list.  Names without quotes are
414         * turned into ALL CAPS and then double quotes are
415         * added; names whcih already have double quotes are
416         * stored exactly as they are. NOTE: DB2 enforces
417         * maximum of 30 tables, and ignores the rest; so
418         * do we.
419         * @param args Array of command line arguments.
420         * @start Position of the start of the list of tables
421         *  with the args array.
422         * @return The position of the last table name in
423         *  the list of table names.
424         ****/
425 
426        private int extractTableNamesFromList(String [] args,
427                int start)
428        {
429 
430                int argIndex = start;
431                int count = 0;
432                tableList = new ArrayList();
433                while (argIndex < args.length) {
434 
435                        if (((args[argIndex].length() > 0) && (args[argIndex].charAt(0) == '-')) ||
436                                (++count > DB2_MAX_NUMBER_OF_TABLES))
437                        // we're done with the table list.
438                                break;
439 
440                        if ((args[argIndex].length() > 0) && (args[argIndex].charAt(0) == '"'))
441                        // it's quoted.
442                                tableList.add(addQuotes(expandDoubleQuotes(
443                                        stripQuotes(args[argIndex++]))));
444                        else
445                        // not quoted, so make it all caps, then add
446                        // quotes.
447                                tableList.add(addQuotes(
448                                        expandDoubleQuotes(args[argIndex++].toUpperCase(
449                                        java.util.Locale.ENGLISH))));
450 
451                }
452 
453                if (tableList.size() == 0)
454                        tableList = null;
455 
456                return argIndex - 1;
457 
458        }
459 
460        /* ************************************************
461         * showVariables:
462         * Echo primary variables to output, so user can see
463         * what s/he specified.
464         ****/
465 
466        private void showVariables() {
467 
468                if (ddlFileName != null) {
469                        Logs.reportString("============================\n");
470                        Logs.reportMessage("DBLOOK_FileCreation");
471                        if (verbose)
472                                writeVerboseOutput("DBLOOK_OutputLocation",
473                                        ddlFileName);
474                }
475 
476                Logs.reportMessage("DBLOOK_Timestamp",
477                        new Timestamp(System.currentTimeMillis()).toString());
478                Logs.reportMessage("DBLOOK_DBName", sourceDBName);
479                Logs.reportMessage("DBLOOK_DBUrl", sourceDBUrl);
480                if (tableList != null)
481                        Logs.reportMessage("DBLOOK_TargetTables");
482                if (schemaParam != null)
483                        Logs.reportMessage("DBLOOK_TargetSchema", stripQuotes(schemaParam));
484                Logs.reportString("appendLogs: " + appendLogs + "\n");
485                return;
486 
487        }
488 
489        /* ************************************************
490         * go:
491         * Connect to the source database, prepare statements,
492         * and load a list of table id-to-name mappings.  Then,
493         * generate the DDL for the various objects in the
494         * database by making calls to static methods of helper
495         * classes (one helper class for each type of database
496         * object).  If a particular object type should not be
497         * generated (because of the user-specified command-
498         * line), then we enforce that here.
499         * @precondition all user-specified parameters have
500         *  been loaded.
501         * @return DDL for the source database has been
502         *  generated and printed to output, subject to
503         *  user-specified restrictions.
504         * ****/
505 
506        private void go()
507                throws Exception
508        {
509 
510                try
511                {
512                        // Connect to the database, prepare statements,
513                        // and load id-to-name mappings.
514                        this.conn = DriverManager.getConnection(sourceDBUrl);
515                        prepForDump();
516 
517                        // Generate DDL.
518 
519                        // Start with schemas, since we might need them to
520                        // exist for jars to load properly.
521                        DB_Schema.doSchemas(this.conn,
522                                (tableList != null) && (targetSchema == null));
523 
524                        if (tableList == null) {
525                        // Don't do these if user just wants table-related objects.
526                                DB_Jar.doJars(sourceDBName, this.conn);
527                                DB_Alias.doProceduresAndFunctions(this.conn);
528                        }
529 
530                        DB_Table.doTables(this.conn, tableIdToNameMap);
531                        DB_Index.doIndexes(this.conn);
532                        DB_Alias.doSynonyms(this.conn);
533                        DB_Key.doKeys(this.conn);
534                        DB_Check.doChecks(this.conn);
535 
536                        if (!skipViews)
537                                DB_View.doViews(this.conn);
538 
539                        DB_Trigger.doTriggers(this.conn);
540 
541                        DB_GrantRevoke.doAuthorizations(this.conn);
542 
543                        // That's it; we're done.
544                        if (getColNameFromNumberQuery != null)
545                                getColNameFromNumberQuery.close();
546                        Logs.cleanup();
547 
548                }
549                catch (SQLException sqlE)
550                {
551                        Logs.debug(sqlE);
552                        Logs.debug(Logs.unRollExceptions(sqlE), (String)null);
553                        Logs.cleanup();
554                        return;
555                }
556                catch (Exception e)
557                {
558                        Logs.debug(e);
559                        Logs.cleanup();
560                        return;
561                }
562                finally {
563                // Close our connection.
564                        if (conn != null) {
565                                conn.commit();
566                                conn.close();
567                        }
568                }
569 
570        }
571 
572        /* ************************************************
573         * prepForDump:
574         * Prepare any useful statements (i.e. statements that
575         * are required by more than one helper class) and load
576         * the id-to-name mappings for the source database.
577         ****/
578 
579        private void prepForDump() throws Exception {
580 
581                // We're only SELECTing throughout all of this, so no need
582                // to commit (plus, disabling commit makes it easier to
583                // have multiple ResultSets open on the same connection).
584                this.conn.setAutoCommit(false);
585 
586                // Prepare statements.
587                getColNameFromNumberQuery = conn.prepareStatement(
588                        "SELECT COLUMNNAME FROM SYS.SYSCOLUMNS WHERE " +
589                        "REFERENCEID = ? AND COLUMNNUMBER = ?");
590 
591                // Load list of user tables and table ids, for general use.
592                Statement stmt = conn.createStatement();
593                ResultSet rs = stmt.executeQuery("SELECT T.TABLEID, T.TABLENAME, " +
594                                "S.SCHEMANAME FROM SYS.SYSTABLES T, SYS.SYSSCHEMAS S " + 
595                                "WHERE T.TABLETYPE = 'T' AND T.SCHEMAID = S.SCHEMAID");
596 
597                while (rs.next()) {
598                        String tableName = addQuotes(expandDoubleQuotes(rs.getString(2)));
599                        String schemaName = addQuotes(expandDoubleQuotes(rs.getString(3)));
600                        tableIdToNameMap.put(rs.getString(1), 
601                                schemaName + "." + tableName);
602                }
603 
604                // Load schema id's and names.
605                rs = stmt.executeQuery("SELECT SCHEMAID, SCHEMANAME FROM " +
606                        "SYS.SYSSCHEMAS");
607                while (rs.next()) {
608                        schemaMap.put(rs.getString(1),
609                                addQuotes(expandDoubleQuotes(rs.getString(2))));
610                }
611 
612                // Check if sqlAuthorization mode is on. If so, need to generate
613                // authorization statements.
614                rs = stmt.executeQuery("VALUES SYSCS_UTIL.SYSCS_GET_DATABASE_PROPERTY" +
615                                                "('derby.database.sqlAuthorization')");
616                if (rs.next())
617                {
618                        String sqlAuth = rs.getString(1);
619                        if (Boolean.valueOf(sqlAuth).booleanValue())
620                                sqlAuthorization = true;
621                }
622                stmt.close();
623 
624                // Load default property values.
625                return;
626 
627        }
628 
629        /* ************************************************
630         * getColumnListFromDescription:
631         * Takes string description of column numbers in the
632         * form of "(2, 1, 3...)" and the id of the table
633         * having those columns, and then returns a string
634         * with the column numbers replaced by their actual
635         * names ('2' is replaced with the 2nd column in the
636         * table, '1' with the first column, etc.).
637         * @param tableId the id of the table to which the column
638         *   numbers should be applied.
639         * @param description a string holding a list of column
640         *  numbers, enclosed in parentheses and separated
641         *  by commas.
642         * @return a new string with the column numbers in
643         *  'description' replaced by their column names;
644         *  also, the parentheses have been stripped off.
645         ****/
646 
647        public static String getColumnListFromDescription(String tableId,
648                String description) throws SQLException
649        {
650 
651                StringBuffer sb = new StringBuffer();
652                StringTokenizer tokenizer = new StringTokenizer(
653                        description.substring(description.indexOf("(") + 1,
654                                description.lastIndexOf(")")), " ,", true);
655 
656                boolean firstCol = true;
657                while (tokenizer.hasMoreTokens()) {
658 
659                        String tok = tokenizer.nextToken().trim();
660                        if (tok.equals(""))
661                                continue;
662                        else if (tok.equals(",")) {
663                                firstCol = false;
664                                continue;
665                        }
666                        try {
667                                String colName = getColNameFromNumber(tableId,
668                                        (Integer.valueOf(tok)).intValue());
669                                if (!firstCol)
670                                        sb.append(", ");
671                                sb.append(colName);
672                        } catch (NumberFormatException e) {
673                        // not a number; could be "ASC" or "DESC" tag,
674                        // which is okay; otherwise, something's wrong.
675                                tok = tok.toUpperCase();
676                                if (tok.equals("DESC") || tok.equals("ASC"))
677                                // then this is okay; just add the token to result.
678                                        sb.append(" " + tok);
679                                else
680                                // shouldn't happen.
681                                        Logs.debug("INTERNAL ERROR: read a non-number (" +
682                                                tok + ") when a column number was expected:\n" +
683                                                description, (String)null);
684                        }
685 
686                }
687 
688                return sb.toString();
689 
690        }
691 
692        /* ************************************************
693         * getColNameFromNumber:
694         * Takes a tableid and a column number colNum, and
695         * returns the name of the colNum'th column in the
696         * table with tableid.
697         * @param tableid id of the table.
698         * @param colNum number of the column for which we want
699         *  the name.
700         * @return The name of the colNum'th column in the
701         *  table with tableid.
702         ****/
703 
704        public static String getColNameFromNumber(String tableId,
705                int colNum) throws SQLException
706        {
707 
708                getColNameFromNumberQuery.setString(1, tableId);
709                getColNameFromNumberQuery.setInt(2, colNum);
710                ResultSet rs = getColNameFromNumberQuery.executeQuery();
711 
712                if (!rs.next()) {
713                // shouldn't happen.
714                        Logs.debug("INTERNAL ERROR: Failed column number " +
715                                "lookup for table " + lookupTableId(tableId) +
716                                ", column " + colNum, (String)null);
717                        rs.close();
718                        return "";
719                }
720                else {
721                        String colName = addQuotes(expandDoubleQuotes(rs.getString(1)));
722                        rs.close();
723                        return colName;
724                }
725 
726        }
727 
728        /* ************************************************
729         * addQuotes:
730         * Add quotes to the received object name, and return
731         * the result.
732         * @param name the name to which to add quotes.
733         * @return the name with double quotes around it.
734         ****/
735 
736        public static String addQuotes(String name) {
737 
738                if (name == null)
739                        return null;
740 
741                return "\"" + name + "\"";
742 
743        }
744 
745 
746        public static String addSingleQuotes(String name) {
747 
748                if (name == null)
749                        return null;
750 
751                return "'" + name + "'";
752        }
753 
754        /* ************************************************
755         * stripQuotes:
756         * Takes a name and, if the name is enclosed in
757         * quotes, strips the quotes off.  This method
758         * assumes that the received String either has no quotes,
759         * or has a quote (double or single) as the very first
760         * AND very last character.
761         * @param quotedName a name with quotes as the first
762         *  and last character, or else with no quotes at all.
763         * @return quotedName, without the quotes.
764         ****/
765 
766        public static String stripQuotes(String quotedName) {
767 
768                if (quotedName == null)
769                        return null;
770 
771                if (!(quotedName.startsWith("'") || quotedName.startsWith("\"")))
772                // name doesn't _start_ with a quote, so we do nothing.
773                        return quotedName;
774 
775                if (!(quotedName.endsWith("'") || quotedName.endsWith("\"")))
776                // name doesn't _end_ with a quote, so we do nothing.
777                        return quotedName;
778 
779                // Remove starting and ending quotes.
780                return quotedName.substring(1, quotedName.length() - 1);
781 
782        }
783 
784        /* ************************************************
785         * isExcludedTable:
786         * Takes a table name and determines whether or not
787         * the DDL for objects related to that table should be
788         * generated.
789         * @param tableName name of the table to check.
790         * @return true if 1) the user specified a table list
791         *  and that list does NOT include the received name; or
792         *  2) if the user specified a schema restriction and
793         *  the received name does NOT have that schema; false
794         *  otherwise.
795         ****/
796 
797        public static boolean isExcludedTable(String tableName) {
798 
799                if (tableName == null)
800                        return true;
801 
802                int dot = tableName.indexOf(".");
803                if (dot != -1) {
804                // strip off the schema part of the name, and see if we're
805                // okay to use it.
806                        if (isIgnorableSchema(tableName.substring(0, dot)))
807                        // then we exclude this table.
808                                return true;
809                        tableName = tableName.substring(dot + 1,
810                                tableName.length());
811                }
812 
813                return ((tableList != null) && !tableList.contains(tableName));
814 
815        }
816 
817        /* ************************************************
818         * Takes a schema name and determines whether or
819         * not the DDL for objects with that schema should
820         * be generated.
821         * @param schemaName schema name to be checked.
822         * @return true if 1) the user specified a target
823         *  schema and that target is NOT the same as the
824         *  received schema name, or 2) the schema is a
825         *  system schema (SYS, SYSVISUAL, or SYSIBM);
826         *  false otherwise;
827         ****/
828 
829    private static final String[] ignorableSchemaNames = {
830        "SYSIBM",
831        "SYS",
832        "SYSVISUAL",
833        "SYSCAT",
834        "SYSFUN",
835        "SYSPROC",
836        "SYSSTAT",
837        "NULLID",
838        "SYSCS_ADMIN",
839        "SYSCS_DIAG",
840        "SYSCS_UTIL",
841        "SQLJ"};
842 
843        public static boolean isIgnorableSchema(String schemaName) {
844 
845                if ((targetSchema != null) && (!schemaName.equals(targetSchema)))
846                        return true;
847 
848                schemaName = stripQuotes(schemaName);
849 
850        boolean ret = false;
851 
852        for (int i = ignorableSchemaNames.length - 1; i >= 0;)
853        {
854            if ((ret = ignorableSchemaNames[i--].equalsIgnoreCase(schemaName)))
855                break;
856        }
857 
858        return(ret);
859        }
860 
861        /* ************************************************
862         * Takes a string and determines whether or not that
863         * string makes reference to any of the table names
864         * in the user-specified table list.
865         * @param str The string in which to search for table names.
866         * @return true if 1) the user didn't specify a
867         *  target table list, or 2) the received string
868         *  contains at least one of the table names in the
869         *  user-specified target list; false otherwise.
870         ****/
871 
872        public static boolean stringContainsTargetTable(String str) {
873 
874                if (str == null)
875                // if the string is null, it can't possibly contain
876                // any table names.
877                        return false;
878 
879                if (tableList == null)
880                // if we have no target tables, then default to true.
881                        return true;
882 
883                int strLen = str.length();
884                for (int i = 0; i < tableList.size(); i++) {
885 
886                        String tableName = (String)tableList.get(i);
887                        tableName = expandDoubleQuotes(stripQuotes(tableName));
888                        int nameLen = tableName.length();
889                        String strCopy;
890                        if (tableName.equals(tableName.toUpperCase(
891                                java.util.Locale.ENGLISH)))
892                        // case doesn't matter.
893                                strCopy = str.toUpperCase();
894                        else
895                                strCopy = str;
896                        int pos = strCopy.indexOf(tableName);
897                        while (pos != -1) {
898 
899                                // If we found it, make sure it's really a match.
900                                // First, see if it's part of another word.
901                                if (!partOfWord(str, pos, nameLen, strLen)) {
902 
903                                        // See if the match is in quotes--if so, then
904                                        // it should match the table name's case.
905                                        if ((pos >= 1) && (strCopy.charAt(pos-1) == '"') &&
906                                          (pos + nameLen < strCopy.length()) &&
907                                          (strCopy.charAt(pos+nameLen) == '"'))
908                                        { // match is quoted; check it's case.
909                                                if (str.substring(pos,
910                                                        pos + nameLen).equals(tableName))
911                                                // everything checks out.
912                                                        return true;
913                                        }
914                                        else
915                                        // match isn't quoted, so we're okay as is.
916                                                return true;
917                                }
918 
919                                pos = str.indexOf(tableName, pos + nameLen);
920 
921                        }
922                }
923 
924                // If we get here, we didn't find it.
925                return false;
926 
927        }
928 
929        /* ************************************************
930         * partOfWord:
931         * Returns true if the part of the string given by
932         * str.substring(pos, pos + nameLen) is part of
933         * another word.
934         * @param str The string in which we're looking.
935         * @param pos The position at which the substring in
936         *  question begins.
937         * @param nameLen the length of the substring in
938         *  question.
939         * @param strLen The length of the string in which
940         *  we're looking.
941         * @return true if the substring from pos to
942         *  pos+nameLen is part of larger word (i.e.
943         *  if it has a letter/digit immediately before
944         *  or after); false otherwise.
945         ****/
946 
947        private static boolean partOfWord (String str,
948                int pos, int nameLen, int strLen)
949        {
950 
951                boolean somethingBefore = false;
952                if (pos > 0) {
953                        char c = str.charAt(pos-1);
954                        somethingBefore = ((c == '_') ||
955                                Character.isLetterOrDigit(c));
956                }
957 
958                boolean somethingAfter = false;
959                if (pos + nameLen < strLen) {
960                        char c = str.charAt(pos + nameLen);
961                        somethingAfter = ((c == '_') ||
962                                Character.isLetterOrDigit(c));
963                }
964 
965                return (somethingBefore || somethingAfter);
966 
967        }
968 
969        /* ************************************************
970         * expandDoubleQuotes:
971         * If the received SQL id contains a quote, we have
972         * to expand it into TWO quotes so that it can be
973         * treated correctly at parse time.
974         * @param name Id that we want to print.
975         ****/
976 
977        public static String expandDoubleQuotes(String name) {
978 
979                if ((name == null) || (name.indexOf("\"") < 0))
980                // nothing to do.
981                        return name;
982 
983                char [] cA = name.toCharArray();
984 
985                // Worst (and extremely unlikely) case is every 
986                // character is a double quote, which means the
987                // escaped string would need to be 2 times as long.
988                char [] result = new char[2*cA.length];
989 
990                int j = 0;
991                for (int i = 0; i < cA.length; i++) {
992 
993                        if (cA[i] == '"') {
994                                result[j++] = '"';
995                                result[j++] = '"';
996                        }
997                        else
998                                result[j++] = cA[i];
999 
1000                }
1001 
1002                return new String(result, 0, j);
1003 
1004        }
1005 
1006        /* ************************************************
1007         * lookupSchemaId:
1008         * Return the schema name corresponding to the
1009         * received schema id.
1010         * @param schemaId The id to look up.
1011         * @return the schema name.
1012         ****/
1013 
1014        public static String lookupSchemaId(String schemaId) {
1015 
1016                return (String)(schemaMap.get(schemaId));
1017 
1018        }
1019 
1020        /* ************************************************
1021         * lookupTableId:
1022         * Return the table name corresponding to the
1023         * received table id.
1024         * @param tableId The id to look up.
1025         * @return the table name.
1026         ****/
1027 
1028        public static String lookupTableId(String tableId) {
1029 
1030                return (String)(tableIdToNameMap.get(tableId));
1031 
1032        }
1033 
1034        /* ************************************************
1035         * writeVerboseOutput:
1036         * Writes the received string as "verbose" output,
1037         * meaning that we write it to System.err.  We
1038         * choose System.err so that the string doesn't
1039         * show up if the user pipes dblook output to
1040         * a file (unless s/he explicitly pipes System.err
1041         * output to that file, as well).
1042         * @param key Key for the message to be printed as
1043         *  verbose output.
1044         * @param value Value to be substituted into the
1045         *  message.
1046         * @return message for received key has been printed
1047         *  to System.err.
1048         ****/
1049 
1050        public static void writeVerboseOutput(String key,
1051                String value) {
1052 
1053                if (value == null)
1054                        System.err.println(lookupMessage(key));
1055                else
1056                        System.err.println(lookupMessage(key,
1057                                new String [] {value}));
1058                return;
1059 
1060        }
1061 
1062        /* ************************************************
1063         * lookupMessage:
1064         * Retrieve a localized message.
1065         * @param key The key for the localized message.
1066         * @return the message corresponding to the received
1067         *  key.
1068         ****/
1069 
1070        public static String lookupMessage(String key) {
1071 
1072                return lookupMessage(key, null);
1073 
1074        }
1075 
1076        /* ************************************************
1077         * lookupMessage:
1078         * Retreive a localized message.
1079         * @param key The key for the localized message.
1080         * @param vals Array of values to be used in the
1081         *   message.
1082         * @return the message corresponding to the received
1083         *  key, with the received values substituted where
1084         *  appropriate.
1085         ****/
1086 
1087        public static String lookupMessage(String key, String[] vals) {
1088        
1089                String msg = "";
1090                if (vals == null)
1091                        msg = langUtil.getTextMessage(key);
1092                else {
1093                        switch (vals.length) {
1094                                case 1: msg = langUtil.getTextMessage(
1095                                                        key, vals[0]);
1096                                                break;
1097                                case 2: msg = langUtil.getTextMessage(
1098                                                        key, vals[0], vals[1]);
1099                                                break;
1100                                default: /* shouldn't happen */
1101                                                break;
1102                        }
1103                }
1104 
1105                return msg;
1106 
1107        }
1108 
1109        /* ************************************************
1110         * removeNewlines:
1111         * Remove any newline characters from the received
1112         * string (replace them with spaces).
1113         * @param str The string from which we are removing
1114         *  all newline characters.
1115         * @return The string, with all newline characters
1116         *  replaced with spaces.
1117         ****/
1118 
1119        public static String removeNewlines(String str) {
1120 
1121                if (str == null)
1122                // don't do anything.
1123                        return null;
1124 
1125                StringBuffer result = null;
1126                try {
1127 
1128                        BufferedReader strVal = new BufferedReader (new StringReader(str));
1129                        for (String txt = strVal.readLine(); txt != null;
1130                                txt = strVal.readLine())
1131                        {
1132                                if (result == null)
1133                                        result = new StringBuffer(txt);
1134                                else {
1135                                        result.append(" ");
1136                                        result.append(txt);
1137                                }
1138                        }
1139 
1140                        return result.toString();
1141 
1142                } catch (Exception e) {
1143                // if something went wrong, just return the string as is--
1144                // worst case is that the generated DDL is correct, it just
1145                // can't be run in some SQL script apps (because of the newline
1146                // characters).
1147                        return str;
1148                }
1149 
1150        }
1151 
1152}
1153 

[all classes][org.apache.derby.tools]
EMMA 2.0.5312 (C) Vladimir Roubtsov