Source Code Cross Referenced for SqlFormatter.java in  » Database-Client » SQL-Workbench » workbench » sql » formatter » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database Client » SQL Workbench » workbench.sql.formatter 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * SqlFormatter.java
0003:         *
0004:         * This file is part of SQL Workbench/J, http://www.sql-workbench.net
0005:         *
0006:         * Copyright 2002-2008, Thomas Kellerer
0007:         * No part of this code maybe reused without the permission of the author
0008:         *
0009:         * To contact the author please send an email to: support@sql-workbench.net
0010:         *
0011:         */
0012:        package workbench.sql.formatter;
0013:
0014:        import java.io.Reader;
0015:        import java.util.ArrayList;
0016:        import java.util.Collections;
0017:        import java.util.HashSet;
0018:        import java.util.List;
0019:        import java.util.Set;
0020:        import java.util.TreeSet;
0021:        import workbench.util.CaseInsensitiveComparator;
0022:        import workbench.resource.Settings;
0023:        import workbench.sql.syntax.SqlKeywordHelper;
0024:        import workbench.sql.wbcommands.CommandTester;
0025:        import workbench.util.CharSequenceReader;
0026:        import workbench.util.StringUtil;
0027:
0028:        /**
0029:         * @author  support@sql-workbench.net
0030:         */
0031:        public class SqlFormatter {
0032:            private final Set<String> LINE_BREAK_BEFORE = new HashSet<String>();
0033:            {
0034:                LINE_BREAK_BEFORE.add("SELECT");
0035:                LINE_BREAK_BEFORE.add("SET");
0036:                LINE_BREAK_BEFORE.add("FROM");
0037:                LINE_BREAK_BEFORE.add("WHERE");
0038:                LINE_BREAK_BEFORE.add("ORDER BY");
0039:                LINE_BREAK_BEFORE.add("GROUP BY");
0040:                LINE_BREAK_BEFORE.add("HAVING");
0041:                LINE_BREAK_BEFORE.add("VALUES");
0042:                LINE_BREAK_BEFORE.add("UNION");
0043:                LINE_BREAK_BEFORE.add("UNION ALL");
0044:                LINE_BREAK_BEFORE.add("MINUS");
0045:                LINE_BREAK_BEFORE.add("INTERSECT");
0046:                LINE_BREAK_BEFORE.add("REFRESH");
0047:                LINE_BREAK_BEFORE.add("AS");
0048:                LINE_BREAK_BEFORE.add("FOR");
0049:                LINE_BREAK_BEFORE.add("INNER JOIN");
0050:                LINE_BREAK_BEFORE.add("RIGHT OUTER JOIN");
0051:                LINE_BREAK_BEFORE.add("LEFT OUTER JOIN");
0052:                LINE_BREAK_BEFORE.add("CROSS JOIN");
0053:                LINE_BREAK_BEFORE.add("LEFT JOIN");
0054:                LINE_BREAK_BEFORE.add("RIGHT JOIN");
0055:                LINE_BREAK_BEFORE.add("START WITH");
0056:                LINE_BREAK_BEFORE.add("CONNECT BY");
0057:            }
0058:
0059:            private final Set<String> LINE_BREAK_AFTER = new HashSet<String>();
0060:            {
0061:                LINE_BREAK_AFTER.add("UNION");
0062:                LINE_BREAK_AFTER.add("UNION ALL");
0063:                LINE_BREAK_AFTER.add("MINUS");
0064:                LINE_BREAK_AFTER.add("INTERSECT");
0065:                LINE_BREAK_AFTER.add("AS");
0066:                LINE_BREAK_AFTER.add("FOR");
0067:            }
0068:
0069:            // keywords terminating a WHERE clause
0070:            public static final Set<String> WHERE_TERMINAL = new HashSet<String>();
0071:            static {
0072:                WHERE_TERMINAL.add("ORDER BY");
0073:                WHERE_TERMINAL.add("GROUP BY");
0074:                WHERE_TERMINAL.add("HAVING");
0075:                WHERE_TERMINAL.add("UNION");
0076:                WHERE_TERMINAL.add("UNION ALL");
0077:                WHERE_TERMINAL.add("INTERSECT");
0078:                WHERE_TERMINAL.add("MINUS");
0079:                WHERE_TERMINAL.add(";");
0080:            }
0081:
0082:            // keywords terminating the FROM part
0083:            public static final Set<String> FROM_TERMINAL = new HashSet<String>();
0084:            static {
0085:                FROM_TERMINAL.addAll(WHERE_TERMINAL);
0086:                FROM_TERMINAL.add("WHERE");
0087:                FROM_TERMINAL.add("START WITH");
0088:                FROM_TERMINAL.add("CONNECT BY");
0089:            }
0090:
0091:            // keywords terminating an GROUP BY clause
0092:            private final Set<String> GROUP_BY_TERMINAL = new HashSet<String>();
0093:            {
0094:                GROUP_BY_TERMINAL.addAll(WHERE_TERMINAL);
0095:                GROUP_BY_TERMINAL.add("SELECT");
0096:                GROUP_BY_TERMINAL.add("UPDATE");
0097:                GROUP_BY_TERMINAL.add("DELETE");
0098:                GROUP_BY_TERMINAL.add("INSERT");
0099:                GROUP_BY_TERMINAL.add("CREATE");
0100:                GROUP_BY_TERMINAL.add("CREATE OR REPLACE");
0101:            }
0102:
0103:            private final Set<String> ORDER_BY_TERMINAL = new HashSet<String>();
0104:            {
0105:                ORDER_BY_TERMINAL.remove("GROUP BY");
0106:                ORDER_BY_TERMINAL.add(";");
0107:            }
0108:
0109:            public static final Set<String> SELECT_TERMINAL = new HashSet<String>(
0110:                    1);
0111:            static {
0112:                SELECT_TERMINAL.add("FROM");
0113:            }
0114:
0115:            private final Set<String> SET_TERMINAL = new HashSet<String>();
0116:            {
0117:                SET_TERMINAL.add("FROM");
0118:                SET_TERMINAL.add("WHERE");
0119:            }
0120:
0121:            private static final Set<String> TABLE_CONSTRAINTS_KEYWORDS = new HashSet<String>();
0122:            {
0123:                TABLE_CONSTRAINTS_KEYWORDS.add("FOREIGN KEY");
0124:                TABLE_CONSTRAINTS_KEYWORDS.add("PRIMARY KEY");
0125:                TABLE_CONSTRAINTS_KEYWORDS.add("CONSTRAINT");
0126:            }
0127:
0128:            private CharSequence sql;
0129:            private SQLLexer lexer;
0130:            private StringBuilder result;
0131:            private StringBuilder indent = null;
0132:            private StringBuilder leadingWhiteSpace = null;
0133:            private int realLength = 0;
0134:            private int maxSubselectLength = 60;
0135:            private Set<String> dbFunctions = Collections.emptySet();
0136:            private Set<String> dataTypes = Collections.emptySet();
0137:            private int selectColumnsPerLine = 1;
0138:            private static final String NL = "\n";
0139:            private boolean lowerCaseFunctions;
0140:
0141:            public SqlFormatter(CharSequence aScript) {
0142:                this (aScript, 0, Settings.getInstance()
0143:                        .getFormatterMaxSubselectLength());
0144:            }
0145:
0146:            public SqlFormatter(CharSequence aScript, int maxSubselectLength) {
0147:                this (aScript, 0, maxSubselectLength);
0148:            }
0149:
0150:            private SqlFormatter(CharSequence aScript, int indentCount,
0151:                    int maxSubselectLength) {
0152:                this .sql = aScript;
0153:                Reader in = new CharSequenceReader(this .sql);
0154:                this .lexer = new SQLLexer(in);
0155:                this .result = new StringBuilder(this .sql.length() + 100);
0156:                if (indentCount > 0) {
0157:                    this .indent = new StringBuilder(indentCount);
0158:                    for (int i = 0; i < indentCount; i++)
0159:                        this .indent.append(' ');
0160:                }
0161:                this .maxSubselectLength = maxSubselectLength;
0162:                this .dbFunctions = new TreeSet<String>(
0163:                        new CaseInsensitiveComparator());
0164:                this .lowerCaseFunctions = Settings.getInstance()
0165:                        .getFormatterLowercaseFunctions();
0166:                addStandardFunctions(dbFunctions);
0167:            }
0168:
0169:            public void setUseLowerCaseFunctions(boolean flag) {
0170:                this .lowerCaseFunctions = flag;
0171:            }
0172:
0173:            public String getLineEnding() {
0174:                return NL;
0175:            }
0176:
0177:            public void setMaxColumnsPerSelect(int cols) {
0178:                this .selectColumnsPerLine = cols;
0179:            }
0180:
0181:            public void setDbDataTypes(Set<String> types) {
0182:                this .dataTypes = types;
0183:            }
0184:
0185:            public void setDBFunctions(Set<String> functionNames) {
0186:                this .dbFunctions = new HashSet<String>();
0187:                if (functionNames != null) {
0188:                    this .dbFunctions.addAll(functionNames);
0189:                }
0190:                addStandardFunctions(dbFunctions);
0191:            }
0192:
0193:            private void addStandardFunctions(Set<String> functions) {
0194:                SqlKeywordHelper keyWords = new SqlKeywordHelper();
0195:                functions.addAll(keyWords.getSystemFunctions());
0196:            }
0197:
0198:            private void saveLeadingWhitespace() {
0199:                if (this .sql.length() == 0)
0200:                    return;
0201:                char c = this .sql.charAt(0);
0202:                int pos = 0;
0203:                if (!Character.isWhitespace(c))
0204:                    return;
0205:
0206:                this .leadingWhiteSpace = new StringBuilder(50);
0207:                while (Character.isWhitespace(c)) {
0208:                    this .leadingWhiteSpace.append(c);
0209:                    pos++;
0210:                    if (pos >= sql.length())
0211:                        break;
0212:                    c = this .sql.charAt(pos);
0213:                }
0214:                this .sql = this .sql.toString().trim();
0215:            }
0216:
0217:            public CharSequence getFormattedSql() throws Exception {
0218:                saveLeadingWhitespace();
0219:                if (this .sql.length() == 0)
0220:                    return sql;
0221:
0222:                this .formatSql();
0223:                StringUtil.trimTrailingWhitespace(result);
0224:                if (this .leadingWhiteSpace != null) {
0225:                    this .result.insert(0, this .leadingWhiteSpace);
0226:                }
0227:                return this .result.toString();
0228:            }
0229:
0230:            private int getRealLength() {
0231:                return this .realLength;
0232:            }
0233:
0234:            public void setMaxSubSelectLength(int max) {
0235:                this .maxSubselectLength = max;
0236:            }
0237:
0238:            private int getCurrentLineLength() {
0239:                int c = this .result.length() - 1;
0240:                int pos = 0;
0241:                while (this .result.charAt(c) != '\n' && c > 0) {
0242:                    pos++;
0243:                    c--;
0244:                }
0245:                return pos;
0246:            }
0247:
0248:            private void appendNewline() {
0249:                if (this .result.length() == 0)
0250:                    return;
0251:                this .result.append(SqlFormatter.NL);
0252:                if (this .indent != null)
0253:                    this .result.append(indent);
0254:            }
0255:
0256:            private boolean lastCharIsWhitespace() {
0257:                int len = this .result.length();
0258:                if (len == 0)
0259:                    return false;
0260:                char c = this .result.charAt(len - 1);
0261:                return Character.isWhitespace(c);
0262:            }
0263:
0264:            private void appendText(char c) {
0265:                this .realLength++;
0266:                this .result.append(c);
0267:            }
0268:
0269:            private void appendTokenText(Token t) {
0270:                String text = t.getContents();
0271:                if (this .lowerCaseFunctions && this .dbFunctions.contains(text)) {
0272:                    text = text.toLowerCase();
0273:                }
0274:                appendText(text);
0275:            }
0276:
0277:            private void appendComment(String text) {
0278:                if (text.startsWith("--")) {
0279:                    if (!this .isStartOfLine())
0280:                        this .appendNewline();
0281:                } else {
0282:                    if (!this .lastCharIsWhitespace())
0283:                        this .appendText(' ');
0284:                }
0285:                this .appendText(text);
0286:                if (text.startsWith("--")) {
0287:                    this .appendNewline();
0288:                } else {
0289:                    this .appendText(' ');
0290:                }
0291:            }
0292:
0293:            private void appendText(String text) {
0294:                this .realLength += text.length();
0295:                this .result.append(text);
0296:            }
0297:
0298:            private void appendText(StringBuilder text) {
0299:                if (text.length() == 0)
0300:                    return;
0301:                this .realLength += text.length();
0302:                this .result.append(text);
0303:            }
0304:
0305:            private void indent(String text) {
0306:                this .result.append(text);
0307:            }
0308:
0309:            private void indent(StringBuilder text) {
0310:                this .result.append(text);
0311:            }
0312:
0313:            private boolean needsWhitespace(SQLToken last, SQLToken current) {
0314:                return this .needsWhitespace(last, current, false);
0315:            }
0316:
0317:            private boolean isDbFunction(String key) {
0318:                if (dbFunctions == null) {
0319:                    SqlKeywordHelper keyWords = new SqlKeywordHelper();
0320:                    dbFunctions = keyWords.getSystemFunctions();
0321:                }
0322:                return this .dbFunctions.contains(key.toUpperCase());
0323:            }
0324:
0325:            private boolean isDatatype(String key) {
0326:                if (dataTypes == null) {
0327:                    SqlKeywordHelper keyWords = new SqlKeywordHelper();
0328:                    dataTypes = keyWords.getDataTypes();
0329:                }
0330:                return this .dataTypes.contains(key.toUpperCase());
0331:            }
0332:
0333:            /**
0334:             * 	Return true if a whitespace should be added before the current token.
0335:             */
0336:            private boolean needsWhitespace(SQLToken last, SQLToken current,
0337:                    boolean ignoreStartOfline) {
0338:                String lastV = last.getContents();
0339:                String currentV = current.getContents();
0340:                char lastChar = lastV.charAt(0);
0341:                char currChar = currentV.charAt(0);
0342:                if (last.isWhiteSpace())
0343:                    return false;
0344:                if (!ignoreStartOfline && this .isStartOfLine())
0345:                    return false;
0346:                boolean isCurrentOpenBracket = "(".equals(currentV);
0347:                boolean isLastOpenBracket = "(".equals(lastV);
0348:                boolean isLastCloseBracket = ")".equals(lastV);
0349:
0350:                if (isCurrentOpenBracket && last.isIdentifier())
0351:                    return false;
0352:                if (isCurrentOpenBracket && isDbFunction(lastV))
0353:                    return false;
0354:                if (isCurrentOpenBracket && isDatatype(lastV))
0355:                    return false;
0356:                if (isCurrentOpenBracket && last.isReservedWord())
0357:                    return true;
0358:                if (isLastCloseBracket && currChar == ',')
0359:                    return false;
0360:                if (isLastCloseBracket
0361:                        && (current.isIdentifier() || current.isReservedWord()))
0362:                    return true;
0363:
0364:                if ((lastChar == '-' || lastChar == '+') && current.isLiteral()
0365:                        && StringUtil.isNumber(currentV))
0366:                    return false;
0367:
0368:                if (last.isLiteral()
0369:                        && (current.isIdentifier() || current.isReservedWord() || current
0370:                                .isOperator()))
0371:                    return true;
0372:
0373:                //if (last.isLiteral() && current.isLiteral()) return false;
0374:
0375:                if (currChar == '?')
0376:                    return true;
0377:                if (currentV.equals("="))
0378:                    return true;
0379:                if (lastV.equals("="))
0380:                    return true;
0381:
0382:                if (lastChar == '.' && current.isIdentifier())
0383:                    return false;
0384:                if (isLastOpenBracket && current.isReservedWord())
0385:                    return false;
0386:                if (isLastCloseBracket && !current.isSeparator())
0387:                    return true;
0388:                if ((last.isIdentifier() || last.isLiteral())
0389:                        && current.isOperator())
0390:                    return true;
0391:                if ((current.isIdentifier() || current.isLiteral())
0392:                        && last.isOperator())
0393:                    return true;
0394:                if (current.isSeparator() || current.isOperator())
0395:                    return false;
0396:                if (last.isOperator()
0397:                        && (current.isReservedWord() || current.isIdentifier() || current
0398:                                .isLiteral()))
0399:                    return true;
0400:                if (last.isSeparator() || last.isOperator())
0401:                    return false;
0402:                return true;
0403:            }
0404:
0405:            private SQLToken processFrom(SQLToken last) throws Exception {
0406:                StringBuilder b = new StringBuilder("     ");
0407:                StringBuilder oldIndent = this .indent;
0408:                //this.indent = null;
0409:                SQLToken t = this .lexer.getNextToken(true, false);
0410:                SQLToken lastToken = last;
0411:                while (t != null) {
0412:                    String text = t.getContents();
0413:
0414:                    if (t.isReservedWord()
0415:                            && FROM_TERMINAL.contains(text.toUpperCase())) {
0416:                        this .indent = oldIndent;
0417:                        return t;
0418:                    } else if (lastToken.isSeparator()
0419:                            && lastToken.getContents().equals("(")
0420:                            && text.equalsIgnoreCase("SELECT")) {
0421:                        t = this .processSubSelect(true);
0422:                        continue;
0423:                    }
0424:
0425:                    if (t.isComment()) {
0426:                        this .appendComment(text);
0427:                    } else if (t.isSeparator() && text.equals("(")) {
0428:                        if ((!lastToken.isSeparator() || lastToken == t)
0429:                                && !this .lastCharIsWhitespace())
0430:                            this .appendText(' ');
0431:                        this .appendText(text);
0432:                    } else if (t.isSeparator() && text.equals(")")) {
0433:                        this .appendText(text);
0434:                    } else if (t.isSeparator() && text.equals(",")) {
0435:                        this .appendText(",");
0436:                        this .appendNewline();
0437:                        this .indent(b);
0438:                    } else {
0439:                        if (this .needsWhitespace(lastToken, t))
0440:                            this .appendText(' ');
0441:                        if (LINE_BREAK_BEFORE.contains(text)
0442:                                && !text.equalsIgnoreCase("AS")) {
0443:                            this .appendNewline();
0444:                            this .indent(b);
0445:                        }
0446:                        this .appendText(text);
0447:                        if (LINE_BREAK_AFTER.contains(text)
0448:                                && !text.equalsIgnoreCase("AS")) {
0449:                            this .appendNewline();
0450:                            this .indent(b);
0451:                        }
0452:                    }
0453:                    lastToken = t;
0454:                    t = this .lexer.getNextToken(true, false);
0455:                }
0456:                this .indent = oldIndent;
0457:                return null;
0458:            }
0459:
0460:            private SQLToken processList(SQLToken last, int indentCount,
0461:                    Set<String> terminalKeys) throws Exception {
0462:                StringBuilder b = new StringBuilder(indentCount);
0463:                for (int i = 0; i < indentCount; i++)
0464:                    b.append(' ');
0465:
0466:                int currentColumnCount = 0;
0467:                boolean isSelect = last.getContents().equals("SELECT");
0468:                SQLToken t = this .lexer.getNextToken(true, false);
0469:                SQLToken lastToken = last;
0470:
0471:                while (t != null) {
0472:                    final String text = t.getContents();
0473:                    if (t.isComment()) {
0474:                        this .appendComment(text);
0475:                    } else if (isSelect && "DECODE".equalsIgnoreCase(text)) {
0476:                        if (this .needsWhitespace(lastToken, t))
0477:                            this .appendText(' ');
0478:                        this .appendText(text);
0479:                        t = processDecode(indentCount);
0480:                        continue;
0481:                    } else if ("CASE".equals(text)) {
0482:                        if (this .needsWhitespace(lastToken, t))
0483:                            this .appendText(' ');
0484:                        this .appendText(text);
0485:                        int caseIndent = indentCount;
0486:                        if (!isSelect) {
0487:                            caseIndent = this .getCurrentLineLength() - 4;
0488:                            this .appendText(' ');
0489:                        }
0490:                        t = processCase(caseIndent);
0491:                        continue;
0492:                    } else if (t.isReservedWord()
0493:                            && terminalKeys.contains(text.toUpperCase())) {
0494:                        return t;
0495:                    } else if (t.isSeparator() && text.equals("(")) {
0496:                        if (this .needsWhitespace(lastToken, t))
0497:                            this .appendText(' ');
0498:                        this .appendText("(");
0499:                        // an equal sign immediately followed by an opening 
0500:                        // bracket cannot be a function call (the function name 
0501:                        // is missing) so it has to be a sub-select
0502:                        if ("=".equals(lastToken.getContents())) {
0503:                            t = this .processSubSelect(false);
0504:                            this .appendTokenText(t);
0505:                        } else {
0506:                            t = this .processFunctionCall(t);
0507:                            if (t == null)
0508:                                return null;
0509:                            if (t.isIdentifier()) {
0510:                                this .appendText(' ');
0511:                                this .appendTokenText(t);
0512:                            }
0513:                        }
0514:                    } else if (t.isSeparator() && text.equals(",")) {
0515:                        this .appendText(',');
0516:                        currentColumnCount++;
0517:                        if (!isSelect
0518:                                || currentColumnCount >= selectColumnsPerLine) {
0519:                            currentColumnCount = 0;
0520:                            this .appendNewline();
0521:                            this .indent(b);
0522:                        } else {
0523:                            this .appendText(' ');
0524:                        }
0525:                    } else if (text.equals("*") && !lastToken.isSeparator()) {
0526:                        this .appendText(" *");
0527:                    } else {
0528:                        if (this .needsWhitespace(lastToken, t))
0529:                            this .appendText(' ');
0530:                        this .appendTokenText(t);
0531:                    }
0532:                    lastToken = t;
0533:                    t = this .lexer.getNextToken(true, false);
0534:                }
0535:                return null;
0536:            }
0537:
0538:            private SQLToken processSubSelect(boolean addSelectKeyword)
0539:                    throws Exception {
0540:                SQLToken t = this .lexer.getNextToken();
0541:                int bracketCount = 1;
0542:                StringBuilder subSql = new StringBuilder(250);
0543:
0544:                // this method gets called when then "parser" hits an
0545:                // IN ( situation. If no SELECT is coming, we assume
0546:                // its a list like IN ('x','Y')
0547:                if (!"SELECT".equalsIgnoreCase(t.getContents())
0548:                        && !addSelectKeyword) {
0549:                    return this .processInList(t);
0550:                }
0551:
0552:                if (addSelectKeyword) {
0553:                    subSql.append("SELECT ");
0554:                }
0555:
0556:                int lastIndent = this .getCurrentLineLength();
0557:
0558:                while (t != null) {
0559:                    String text = t.getContents();
0560:                    if (text.equals(")")) {
0561:                        bracketCount--;
0562:
0563:                        if (bracketCount == 0) {
0564:                            appendSubSelect(subSql, lastIndent);
0565:                            return t;
0566:                        }
0567:                    } else if (t.isSeparator() && text.equals("(")) {
0568:                        bracketCount++;
0569:                    }
0570:                    subSql.append(text);
0571:                    t = this .lexer.getNextToken();
0572:                }
0573:                this .appendText(subSql);
0574:                return t;
0575:            }
0576:
0577:            private void appendSubSelect(StringBuilder subSql, int lastIndent)
0578:                    throws Exception {
0579:                SqlFormatter f = new SqlFormatter(subSql.toString(),
0580:                        lastIndent, this .maxSubselectLength);
0581:                String s = f.getFormattedSql().toString();
0582:                if (f.getRealLength() < this .maxSubselectLength) {
0583:                    s = s.replaceAll(" *" + SqlFormatter.NL + " *", " ");
0584:                }
0585:                this .appendText(s.trim());
0586:            }
0587:
0588:            private SQLToken processDecode(int indent) throws Exception {
0589:                StringBuilder current = new StringBuilder(indent);
0590:
0591:                for (int i = 0; i < indent; i++)
0592:                    current.append(' ');
0593:
0594:                StringBuilder b = new StringBuilder(indent + 2);
0595:                for (int i = 0; i < indent; i++)
0596:                    b.append(' ');
0597:                b.append("      ");
0598:
0599:                boolean newLinePending = false;
0600:
0601:                SQLToken t = this .lexer.getNextToken(true, true);
0602:                int commaCount = 0;
0603:                int bracketCount = 0;
0604:
0605:                boolean inQuotes = false;
0606:                while (t != null) {
0607:                    final String text = t.getContents();
0608:                    if ("'".equals(text)) {
0609:                        inQuotes = !inQuotes;
0610:                    } else if (")".equals(text)) {
0611:                        bracketCount--;
0612:                    } else if ("(".equals(text)) {
0613:                        bracketCount++;
0614:                    }
0615:
0616:                    if (",".equals(text) && !inQuotes && bracketCount == 1)
0617:                        commaCount++;
0618:
0619:                    if (",".equals(text) && !inQuotes && bracketCount == 1) {
0620:                        this .appendText(text);
0621:                        if (commaCount % 2 == 1) {
0622:                            this .appendNewline();
0623:                            this .indent(b);
0624:                        }
0625:                    } else if (")".equalsIgnoreCase(text) && !inQuotes
0626:                            && bracketCount == 0) {
0627:                        this .appendNewline();
0628:                        this .indent(current);
0629:                        this .appendText(") ");
0630:                        t = this .lexer.getNextToken(true, false);
0631:                        return t;
0632:                    } else if (text.indexOf("\n") == -1
0633:                            && text.indexOf("\r") == -1) {
0634:                        this .appendTokenText(t);
0635:                    }
0636:                    t = this .lexer.getNextToken(true, true);
0637:                }
0638:                return null;
0639:            }
0640:
0641:            private SQLToken processCase(int indent) throws Exception {
0642:                StringBuilder current = new StringBuilder(indent);
0643:
0644:                for (int i = 0; i < indent; i++)
0645:                    current.append(' ');
0646:
0647:                StringBuilder b = new StringBuilder(indent + 2);
0648:                for (int i = 0; i < indent; i++)
0649:                    b.append(' ');
0650:                b.append("  ");
0651:
0652:                SQLToken last = null;
0653:                SQLToken t = this .lexer.getNextToken(true, false);
0654:                while (t != null) {
0655:                    final String text = t.getContents();
0656:
0657:                    if ("SELECT".equals(text) && last.getContents().equals("(")) {
0658:                        t = this .processSubSelect(true);
0659:                        if (t == null)
0660:                            return null;
0661:                        if (t.getContents().equals(")"))
0662:                            this .appendText(")");
0663:                    } else if ("WHEN".equals(text) || "ELSE".equals(text)) {
0664:                        this .appendNewline();
0665:                        this .indent(b);
0666:                        this .appendText(text);
0667:                        appendText(' ');
0668:                    } else if ("THEN".equals(text)) {
0669:                        if (last != null && this .needsWhitespace(last, t))
0670:                            appendText(' ');
0671:                        this .appendText(text);
0672:                        appendText(' ');
0673:                    } else if ("END".equals(text) || "END CASE".equals(text)) {
0674:                        this .appendNewline();
0675:                        this .indent(current);
0676:                        this .appendText(text);
0677:                        // Get the next token after the END. If that is the keyword AS, 
0678:                        // the CASE statement ist not yet ended and we have to add the AS keyword
0679:                        // and the alias that was given before returning to the caller
0680:                        t = this .lexer.getNextToken(true, false);
0681:                        if (t != null && t.getContents().equals("AS")) {
0682:                            this .appendText(' ');
0683:                            this .appendText(t.getContents());
0684:                            t = this .lexer.getNextToken(true, false);
0685:                            if (t != null) {
0686:                                this .appendText(' ');
0687:                                this .appendText(t.getContents());
0688:                                t = this .lexer.getNextToken(true, false);
0689:                            }
0690:                        }
0691:                        this .appendNewline();
0692:                        return t;
0693:                    } else if (t.isComment()) {
0694:                        this .appendComment(text);
0695:                    } else if (!t.isWhiteSpace()) {
0696:                        this .appendTokenText(t);
0697:                    }
0698:                    last = t;
0699:                    t = this .lexer.getNextToken(true, false);
0700:                }
0701:                return null;
0702:            }
0703:
0704:            private SQLToken processWbCommand(int indent) throws Exception {
0705:                StringBuilder b = new StringBuilder(indent);
0706:
0707:                for (int i = 0; i < indent; i++)
0708:                    b.append(' ');
0709:                this .appendText(' ');
0710:
0711:                SQLToken t = this .lexer.getNextToken(true, false);
0712:                boolean first = true;
0713:                boolean isParm = false;
0714:                boolean inQuotes = false;
0715:                while (t != null) {
0716:                    String text = inQuotes ? t.getText() : t.getContents();
0717:                    if (text.equals("'") || text.equals("\"")) {
0718:                        inQuotes = !inQuotes;
0719:                    }
0720:                    if (isParm)
0721:                        text = text.toLowerCase();
0722:                    if (text.equals("-") && !inQuotes) {
0723:                        if (!first) {
0724:                            this .appendNewline();
0725:                            this .indent(b);
0726:                        }
0727:                        isParm = true;
0728:                    } else {
0729:                        isParm = false;
0730:                    }
0731:                    this .appendText(text);
0732:                    t = this .lexer.getNextToken(true, inQuotes);
0733:                    first = false;
0734:                }
0735:                return null;
0736:            }
0737:
0738:            private SQLToken processBracketList(int indentCount)
0739:                    throws Exception {
0740:                StringBuilder b = new StringBuilder(indentCount);
0741:
0742:                for (int i = 0; i < indentCount; i++)
0743:                    b.append(' ');
0744:
0745:                this .appendText(b);
0746:                SQLToken t = this .lexer.getNextToken(true, false);
0747:
0748:                while (t != null) {
0749:                    final String text = t.getContents();
0750:                    if (text.equals(")")) {
0751:                        this .appendNewline();
0752:                        //this.indent(b);
0753:                        this .appendText(")");
0754:                        return this .lexer.getNextToken();
0755:                    } else if (text.equals("(")) {
0756:                        this .appendText(" (");
0757:                        t = this .processFunctionCall(t);
0758:                        continue;
0759:                    } else if (text.equals(",")) {
0760:                        this .appendText(",");
0761:                        this .appendNewline();
0762:                        this .indent(b);
0763:                    } else if (!t.isWhiteSpace()) {
0764:                        this .appendTokenText(t);
0765:                        if (t.isComment())
0766:                            this .appendText(' ');
0767:                    }
0768:                    t = this .lexer.getNextToken(true, false);
0769:                }
0770:                return null;
0771:            }
0772:
0773:            private SQLToken processInList(SQLToken current) throws Exception {
0774:                ArrayList<StringBuilder> list = new ArrayList<StringBuilder>(25);
0775:                list.add(new StringBuilder(""));
0776:                SQLToken t = current;
0777:
0778:                int bracketcount = 0;
0779:                int elementcounter = 0;
0780:
0781:                while (t != null) {
0782:                    String text = t.getContents();
0783:                    if (t.isSeparator() && text.equals(")")) {
0784:                        if (bracketcount == 0) {
0785:                            this .appendCommaList(list);
0786:                            return this .lexer.getNextToken();
0787:                        } else {
0788:                            StringBuilder b = list.get(elementcounter);
0789:                            if (b == null) {
0790:                                b = new StringBuilder(text);
0791:                                if (elementcounter < list.size())
0792:                                    list.set(elementcounter, b);
0793:                            } else {
0794:                                b.append(text);
0795:                            }
0796:                        }
0797:                    } else if (t.isSeparator() && text.equals("(")) {
0798:                        bracketcount++;
0799:                    } else if (t.isSeparator() && text.equals(",")) {
0800:                        if (bracketcount == 0) {
0801:                            list.add(new StringBuilder(""));
0802:                            elementcounter = list.size() - 1;
0803:                        }
0804:                    } else if (!t.isWhiteSpace()) {
0805:                        StringBuilder b = list.get(elementcounter);
0806:                        if (b == null) {
0807:                            b = new StringBuilder(text);
0808:                            if (t.isComment())
0809:                                b.append(' ');
0810:                            list.set(elementcounter, b);
0811:                        } else {
0812:                            b.append(text);
0813:                            if (t.isComment())
0814:                                b.append(' ');
0815:                        }
0816:                    }
0817:                    t = this .lexer.getNextToken(true, false);
0818:                }
0819:                return null;
0820:            }
0821:
0822:            private void appendCommaList(ArrayList aList) {
0823:                int indentCount = this .getCurrentLineLength();
0824:                StringBuilder ind = new StringBuilder(indentCount);
0825:                for (int i = 0; i < indentCount; i++)
0826:                    ind.append(' ');
0827:                boolean newline = (aList.size() > 10);
0828:                int count = aList.size();
0829:                for (int i = 0; i < count; i++) {
0830:                    this .appendText((StringBuilder) aList.get(i));
0831:                    if (i < count - 1)
0832:                        this .appendText(", ");
0833:                    if (newline) {
0834:                        this .appendNewline();
0835:                        this .indent(ind);
0836:                    }
0837:                }
0838:                this .appendText(")");
0839:            }
0840:
0841:            private boolean isStartOfLine() {
0842:                int len = this .result.length();
0843:                if (len == 0)
0844:                    return true;
0845:
0846:                // simulates endsWith() on a StringBuilder
0847:                int pos = result.lastIndexOf(SqlFormatter.NL);
0848:                if (pos == len - NL.length())
0849:                    return true;
0850:
0851:                // Current text does not end with a newline, but
0852:                // if the "current line" consist of the current indent, it 
0853:                // is considered as a "start of line" as well.
0854:                String remain = result.substring(pos + NL.length());
0855:                int indentLength = (indent == null ? 0 : indent.length());
0856:                if (remain.trim().length() == 0
0857:                        && remain.length() == indentLength)
0858:                    return true;
0859:                return false;
0860:            }
0861:
0862:            private void formatSql() throws Exception {
0863:                SQLToken t = this .lexer.getNextToken(true, false);
0864:                SQLToken lastToken = t;
0865:                CommandTester wbTester = new CommandTester();
0866:
0867:                while (t != null) {
0868:                    final String word = t.getContents().toUpperCase();
0869:                    if (t.isComment()) {
0870:                        String text = t.getContents();
0871:                        this .appendComment(text);
0872:                    } else if (t.isReservedWord()) {
0873:                        if (lastToken.isComment() && !isStartOfLine())
0874:                            this .appendNewline();
0875:
0876:                        if (LINE_BREAK_BEFORE.contains(word)) {
0877:                            if (!isStartOfLine())
0878:                                this .appendNewline();
0879:
0880:                            // For UPDATE statements
0881:                            if ("SET".equals(word)) {
0882:                                this .indent("   ");
0883:                            }
0884:                        } else {
0885:                            //if (!lastToken.isSeparator() && lastToken != t && !isStartOfLine()) this.appendText(' ');
0886:                            if (needsWhitespace(lastToken, t))
0887:                                this .appendText(' ');
0888:                        }
0889:
0890:                        if (wbTester.isWbCommand(word)) {
0891:                            this .appendText(wbTester.formatVerb(word));
0892:                        } else {
0893:                            this .appendTokenText(t);
0894:                        }
0895:
0896:                        if (LINE_BREAK_AFTER.contains(word)) {
0897:                            this .appendNewline();
0898:                        }
0899:
0900:                        if (word.equals("SELECT")) {
0901:                            lastToken = t;
0902:                            t = this .processList(t, "SELECT".length() + 1,
0903:                                    SELECT_TERMINAL);
0904:                            if (t == null)
0905:                                return;
0906:                            continue;
0907:                        }
0908:
0909:                        if (word.equals("SET")) {
0910:                            lastToken = t;
0911:                            t = this .processList(t, "SET".length() + 4,
0912:                                    SET_TERMINAL);
0913:                            if (t == null)
0914:                                return;
0915:                            continue;
0916:                        }
0917:
0918:                        if (word.equals("CREATE")
0919:                                || word.equals("CREATE OR REPLACE")) {
0920:                            lastToken = t;
0921:                            t = this .processCreate(t);
0922:                            if (t == null)
0923:                                return;
0924:                            continue;
0925:                        }
0926:
0927:                        if (word.equals("FROM")) {
0928:                            lastToken = t;
0929:                            t = this .processFrom(t);
0930:                            if (t == null)
0931:                                return;
0932:                            continue;
0933:                        }
0934:
0935:                        if (word.equals("GROUP BY")) {
0936:                            lastToken = t;
0937:                            t = this .processList(lastToken, (word + " ")
0938:                                    .length(), GROUP_BY_TERMINAL);
0939:                            if (t == null)
0940:                                return;
0941:                            continue;
0942:                        }
0943:
0944:                        if (word.equals("ORDER BY")) {
0945:                            lastToken = t;
0946:                            t = this .processList(lastToken, (word + " ")
0947:                                    .length(), ORDER_BY_TERMINAL);
0948:                            if (t == null)
0949:                                return;
0950:                        }
0951:
0952:                        if (word.equalsIgnoreCase("WHERE")) {
0953:                            lastToken = t;
0954:                            t = this .processWhere(t);
0955:                            if (t == null)
0956:                                return;
0957:                            continue;
0958:                        }
0959:
0960:                        if (word.equalsIgnoreCase("INTO")) {
0961:                            lastToken = t;
0962:                            t = this .processIntoKeyword();
0963:                            continue;
0964:                        }
0965:
0966:                        if (word.equalsIgnoreCase("VALUES")) {
0967:                            // the next (non-whitespace token has to be a (
0968:                            t = this .lexer.getNextToken(false, false);
0969:                            if (t.isSeparator() && t.getContents().equals("(")) {
0970:                                this .appendNewline();
0971:                                this .appendText("(");
0972:                                this .appendNewline();
0973:
0974:                                t = this .processBracketList(2);
0975:                            }
0976:                            if (t == null)
0977:                                return;
0978:                            continue;
0979:                        }
0980:
0981:                        if (wbTester.isWbCommand(word)) {
0982:                            t = this .processWbCommand(word.length() + 1);
0983:                        }
0984:
0985:                    } else {
0986:                        if (LINE_BREAK_BEFORE.contains(word)) {
0987:                            if (!isStartOfLine())
0988:                                this .appendNewline();
0989:                        }
0990:
0991:                        if (word.equals("(")) {
0992:                            if (this .needsWhitespace(lastToken, t))
0993:                                this .appendText(' ');
0994:                            this .appendText('(');
0995:                            t = this .processFunctionCall(t);
0996:                        } else {
0997:                            if (word.equals(";")) {
0998:                                this .appendText(word);
0999:                                this .appendNewline();
1000:                                this .appendNewline();
1001:                            } else {
1002:                                if (this .needsWhitespace(lastToken, t))
1003:                                    this .appendText(' ');
1004:                                this .appendText(t.getContents());
1005:                            }
1006:                        }
1007:                    }
1008:                    lastToken = t;
1009:                    t = this .lexer.getNextToken(true, false);
1010:                }
1011:                //		this.appendNewline();
1012:                //		this.appendNewline();
1013:            }
1014:
1015:            private SQLToken processWhere(SQLToken previousToken)
1016:                    throws Exception {
1017:                SQLToken t = this .lexer.getNextToken(true, false);
1018:                SQLToken lastToken = previousToken;
1019:                int bracketCount = 0;
1020:                while (t != null) {
1021:                    String verb = t.getContents();
1022:
1023:                    if (t.isReservedWord() && WHERE_TERMINAL.contains(verb)) {
1024:                        return t;
1025:                    }
1026:
1027:                    if (verb.equals(";")) {
1028:                        return t;
1029:                    }
1030:
1031:                    if (verb.equals(")")) {
1032:                        bracketCount--;
1033:                        this .appendText(")");
1034:                    } else if (t.isComment()) {
1035:                        this .appendComment(verb);
1036:                    } else if (t.getContents().equals("(")) {
1037:                        String lastWord = lastToken.getContents();
1038:
1039:                        if (lastWord != null)
1040:                            lastWord = lastWord.toUpperCase();
1041:                        if (!lastToken.isSeparator()
1042:                                && !this .dbFunctions.contains(lastWord))
1043:                            this .appendText(' ');
1044:                        this .appendText(t.getContents());
1045:
1046:                        SQLToken next = skipComments();
1047:                        if (next == null)
1048:                            return null;
1049:
1050:                        if ("SELECT".equals(next.getContents())) {
1051:                            t = this .processSubSelect(true);
1052:                            if (t == null)
1053:                                return null;
1054:                            if (t.getContents().equals(")"))
1055:                                this .appendText(")");
1056:                        } else {
1057:                            bracketCount++;
1058:
1059:                            lastToken = t;
1060:                            t = next;
1061:                            continue;
1062:                        }
1063:                    } else if (bracketCount == 0 && t.isReservedWord()
1064:                            && (verb.equals("AND") || verb.equals("OR"))) {
1065:                        // TODO: this attempt to keep conditions in bracktes together results
1066:                        // in effectively no formatting when the whole WHERE clause is put 
1067:                        // between brackets (because bracketCount will never be zero until 
1068:                        // the end of the WHERE clause)
1069:                        if (!this .isStartOfLine())
1070:                            this .appendNewline();
1071:                        this .appendText(verb);
1072:                        this .appendText("  ");
1073:                        if (verb.equals("OR"))
1074:                            this .appendText(' ');
1075:                    } else {
1076:                        if (this .needsWhitespace(lastToken, t))
1077:                            this .appendText(' ');
1078:                        this .appendText(verb);
1079:                    }
1080:
1081:                    lastToken = t;
1082:                    t = this .lexer.getNextToken(true, false);
1083:                }
1084:                return null;
1085:            }
1086:
1087:            private SQLToken skipComments() throws Exception {
1088:                SQLToken next = lexer.getNextToken(true, false);
1089:                if (!next.isComment())
1090:                    return next;
1091:                while (next != null) {
1092:                    if (!next.isComment())
1093:                        return next;
1094:                    this .appendComment(next.getContents());
1095:                    next = lexer.getNextToken(true, false);
1096:                }
1097:                return null;
1098:            }
1099:
1100:            private SQLToken processIntoKeyword() throws Exception {
1101:                SQLToken t = this .lexer.getNextToken(false, false);
1102:                // we expect an identifier now (the table name)
1103:                // but to be able to handle "wrong statements" we'll
1104:                // make sure everything's fine
1105:
1106:                if (t.isIdentifier()) {
1107:                    this .appendText(' ');
1108:                    this .appendText(t.getContents());
1109:                    t = this .lexer.getNextToken(false, false);
1110:                    if (t.getContents().equalsIgnoreCase("VALUES")) {
1111:                        // no column list to format here...
1112:                        return t;
1113:                    } else if (t.isSeparator() && t.getContents().equals("(")) {
1114:                        this .appendNewline();
1115:                        this .appendText(t.getContents());
1116:                        this .appendNewline();
1117:                        return this .processBracketList(2);
1118:                    }
1119:                }
1120:                return t;
1121:            }
1122:
1123:            private SQLToken processFunctionCall(SQLToken last)
1124:                    throws Exception {
1125:                int bracketCount = 1;
1126:                SQLToken t = this .lexer.getNextToken(true, false);
1127:
1128:                if (t != null && t.getContents().equals("SELECT")) {
1129:                    t = processSubSelect(true);
1130:                    if (t == null)
1131:                        return null;
1132:                    if (t.getContents().equals(")")) {
1133:                        this .appendText(')');
1134:                        SQLToken l = t;
1135:                        t = this .lexer.getNextToken(true, false);
1136:                    }
1137:                    return t;
1138:                }
1139:
1140:                SQLToken lastToken = last;
1141:                while (t != null) {
1142:                    String text = t.getContents();
1143:                    if (text.equals(")")) {
1144:                        bracketCount--;
1145:                    }
1146:                    if (text.equals("(")) {
1147:                        bracketCount++;
1148:                    }
1149:                    if (this .needsWhitespace(lastToken, t))
1150:                        this .appendText(' ');
1151:                    this .appendText(t.getContents());
1152:
1153:                    if (bracketCount == 0) {
1154:                        return t;
1155:                    }
1156:                    lastToken = t;
1157:                    t = this .lexer.getNextToken(true, false);
1158:                }
1159:                return null;
1160:            }
1161:
1162:            private SQLToken processCreate(SQLToken previous) throws Exception {
1163:                SQLToken t = this .lexer.getNextToken(true, false);
1164:                String verb = t.getContents();
1165:                int createStart = t.getCharBegin();
1166:
1167:                if (verb.equals("TABLE")) {
1168:                    this .appendText(' ');
1169:                    this .appendText(t.getContents());
1170:                    this .appendText(' ');
1171:                    t = this .processCreateTable(t);
1172:                    return t;
1173:                } else if (verb.equals("VIEW") || verb.equals("SNAPSHOT")) {
1174:                    this .appendText(' ');
1175:                    this .appendText(verb);
1176:                    this .appendText(' ');
1177:                    return this .processCreateView(t);
1178:                } else if (verb.equals("INDEX")) {
1179:                    this .appendText(' ');
1180:                    this .appendText(verb);
1181:                    //this.appendText(' ');
1182:                    return this .processCreateIndex(t);
1183:                } else if (verb.equals("OR")) {
1184:                    // Check for Oracle's CREATE OR REPLACE
1185:                    this .appendText(' ');
1186:                    this .appendText(verb);
1187:                    t = this .lexer.getNextToken(true, false);
1188:                    if (t == null)
1189:                        return t;
1190:                    verb = t.getContents();
1191:                    if (verb.equals("REPLACE")) {
1192:                        this .appendText(' ');
1193:                        this .appendText(verb);
1194:                        this .appendText(' ');
1195:                        return this .processCreateView(t);
1196:                    }
1197:                }
1198:
1199:                return t;
1200:            }
1201:
1202:            private boolean isTableConstraint(String keyword) {
1203:                return TABLE_CONSTRAINTS_KEYWORDS.contains(keyword);
1204:            }
1205:
1206:            private SQLToken processTableDefinition() {
1207:                List<StringBuilder> cols = new ArrayList<StringBuilder>();
1208:                SQLToken t = lexer.getNextToken(true, false);
1209:                StringBuilder line = new StringBuilder(50);
1210:                int maxColLength = 0;
1211:
1212:                boolean isColname = true;
1213:                int bracketCount = 0;
1214:
1215:                SQLToken last = null;
1216:
1217:                while (t != null) {
1218:                    String w = t.getContents();
1219:
1220:                    if (isTableConstraint(w)) {
1221:                        // end of column definitions reached
1222:                        break;
1223:                    }
1224:
1225:                    if ("(".equals(w))
1226:                        bracketCount++;
1227:                    if (")".equals(w))
1228:                        bracketCount--;
1229:
1230:                    // Closing bracket reached --> end of 
1231:                    if (bracketCount < 0) {
1232:                        cols.add(line);
1233:                        break;
1234:                    }
1235:
1236:                    if (!isColname && last != null
1237:                            && needsWhitespace(last, t, true)) {
1238:                        line.append(' ');
1239:                    }
1240:                    line.append(w);
1241:
1242:                    if (isColname && t.isIdentifier()) {
1243:                        if (w.length() > maxColLength)
1244:                            maxColLength = w.length();
1245:                        isColname = false;
1246:                    }
1247:
1248:                    if (w.equals(",") && bracketCount == 0) {
1249:                        cols.add(line);
1250:                        line = new StringBuilder(50);
1251:                        isColname = true;
1252:                    }
1253:
1254:                    last = t;
1255:                    t = this .lexer.getNextToken(true, false);
1256:                }
1257:
1258:                // Now process the collected column definitions
1259:                for (StringBuilder col : cols) {
1260:                    int pos = StringUtil.findFirstWhiteSpace(col);
1261:                    String colname = col.substring(0, pos).trim();
1262:                    String def = col.substring(pos + 1).trim();
1263:                    appendText("  ");
1264:                    appendText(colname);
1265:                    while (pos < maxColLength) {
1266:                        this .appendText(' ');
1267:                        pos++;
1268:                    }
1269:                    this .appendText("   ");
1270:                    appendText(def);
1271:                    appendNewline();
1272:                }
1273:
1274:                if (t == null)
1275:                    return t;
1276:
1277:                // now the definitions are added
1278:                // check if we need to process more
1279:                if (!t.getContents().equals(")")) {
1280:                    appendText("  ");
1281:                    bracketCount = 0;
1282:                    last = null;
1283:
1284:                    while (t != null) {
1285:                        String w = t.getContents();
1286:                        if ("(".equals(w))
1287:                            bracketCount++;
1288:
1289:                        if (")".equals(w)) {
1290:                            if (bracketCount == 0) {
1291:                                break;
1292:                            } else {
1293:                                bracketCount--;
1294:                            }
1295:                        }
1296:
1297:                        if (last != null && needsWhitespace(last, t, true)) {
1298:                            appendText(' ');
1299:                        }
1300:                        appendText(w);
1301:
1302:                        if (",".equals(w) && bracketCount == 0) {
1303:                            this .appendNewline();
1304:                            this .appendText("  ");
1305:                        }
1306:
1307:                        last = t;
1308:                        t = this .lexer.getNextToken(true, false);
1309:                    }
1310:                    appendNewline();
1311:                }
1312:
1313:                appendText(')');
1314:                appendNewline();
1315:                t = this .lexer.getNextToken(false, false);
1316:
1317:                return t;
1318:            }
1319:
1320:            /**
1321:             * Process a CREATE TABLE statement. 
1322:             * The CREATE TABLE has already been added!
1323:             */
1324:            private SQLToken processCreateTable(SQLToken previous)
1325:                    throws Exception {
1326:                SQLToken t = this .lexer.getNextToken(false, false);
1327:                if (t == null)
1328:                    return t;
1329:
1330:                // the next token has to be the table name, so 
1331:                // we can simply write it out
1332:
1333:                this .appendText(t.getContents());
1334:                this .appendText(' ');
1335:
1336:                t = this .lexer.getNextToken(false, false);
1337:                if (t == null)
1338:                    return t;
1339:
1340:                // this has to be the opening bracket before the table definition
1341:                this .appendNewline();
1342:                this .appendText('(');
1343:                this .appendNewline();
1344:
1345:                t = processTableDefinition();
1346:
1347:                return t;
1348:            }
1349:
1350:            /**
1351:             *	Process the elements in a () combination
1352:             *	Any bracket inside the brackets are assumed to be "function calls"
1353:             *  and just treated as further elements.
1354:             *	It is assumed that the passed SQLToken is the opening bracket
1355:             * 
1356:             *  @return the token after the closing bracket
1357:             */
1358:            private SQLToken processCommaList(SQLToken previous,
1359:                    int maxElements, int indentCount) throws Exception {
1360:                StringBuilder definition = new StringBuilder(200);
1361:                SQLToken t = previous;
1362:                SQLToken last = previous;
1363:                int bracketCount = 0;
1364:
1365:                while (t != null) {
1366:                    if (t.getContents().equals("(")) {
1367:                        if (bracketCount > 0) {
1368:                            definition.append('(');
1369:                        }
1370:                        bracketCount++;
1371:                    } else if (t.getContents().equals(")")) {
1372:                        if (bracketCount == 1) {
1373:                            List elements = StringUtil.stringToList(definition
1374:                                    .toString(), ",");
1375:                            this .outputElements(elements, maxElements,
1376:                                    indentCount);
1377:                            return this .lexer.getNextToken(true, false);
1378:                        } else {
1379:                            definition.append(')');
1380:                        }
1381:                        bracketCount--;
1382:                    } else if (bracketCount > 0) {
1383:                        if (this .needsWhitespace(last, t, true)) {
1384:                            definition.append(' ');
1385:                        }
1386:                        definition.append(t.getContents());
1387:                    }
1388:                    last = t;
1389:                    t = this .lexer.getNextToken(true, false);
1390:                }
1391:                return t;
1392:            }
1393:
1394:            /*
1395:             *	Output the elements of the given List comma separated
1396:             *  If the list contains more elements, then maxElements
1397:             *  each element will be put on a single line
1398:             *	If more then one line is "printed" they will be indented by
1399:             *  indentCount spaces
1400:             */
1401:            private void outputElements(List elements, int maxElements,
1402:                    int indentCount) {
1403:                StringBuilder myIndent = new StringBuilder(indentCount);
1404:                for (int i = 0; i < indentCount; i++)
1405:                    myIndent.append(' ');
1406:
1407:                int count = elements.size();
1408:
1409:                if (count > maxElements) {
1410:                    this .appendNewline();
1411:                    this .indent(myIndent);
1412:                    this .appendText("(");
1413:                } else {
1414:                    this .appendText(" (");
1415:                }
1416:
1417:                if (count > maxElements) {
1418:                    this .appendNewline();
1419:                    this .indent(myIndent);
1420:                    this .indent("  ");
1421:                }
1422:
1423:                for (int i = 0; i < count; i++) {
1424:                    String text = (String) elements.get(i);
1425:                    this .appendText(text);
1426:                    if (i < count - 1) {
1427:                        if (count > maxElements) {
1428:                            this .appendText(',');
1429:                            this .appendNewline();
1430:                            this .indent(myIndent);
1431:                            this .indent("  ");
1432:                        } else {
1433:                            this .appendText(", ");
1434:                        }
1435:                    }
1436:                }
1437:                if (count > maxElements) {
1438:                    this .appendNewline();
1439:                    this .indent(myIndent);
1440:                }
1441:                this .appendText(")");
1442:            }
1443:
1444:            /**
1445:             * Format a CREATE VIEW statement
1446:             */
1447:            private SQLToken processCreateView(SQLToken previous)
1448:                    throws Exception {
1449:                SQLToken t = this .lexer.getNextToken(false, false);
1450:                SQLToken last = previous;
1451:                int bracketCount = 0;
1452:                StringBuilder definition = new StringBuilder(200);
1453:
1454:                while (t != null) {
1455:                    if (t.getContents().equals("(")) {
1456:                        if (bracketCount == 0) {
1457:                            // start of column definitions...
1458:                            t = this .processCommaList(t, 1, 0);
1459:                        }
1460:                        bracketCount++;
1461:                    }
1462:
1463:                    if ("SELECT".equals(t.getContents())) {
1464:                        return t;
1465:                    } else if ("AS".equals(t.getContents())) {
1466:                        this .appendNewline();
1467:                        this .appendText(t.getContents());
1468:                        this .appendNewline();
1469:                    } else {
1470:                        this .appendText(t.getContents());
1471:                        if (this .needsWhitespace(last, t, true)) {
1472:                            this .appendText(' ');
1473:                        }
1474:                    }
1475:                    last = t;
1476:                    t = this .lexer.getNextToken(false, false);
1477:                }
1478:                return t;
1479:            }
1480:
1481:            private SQLToken processCreateIndex(SQLToken previous)
1482:                    throws Exception {
1483:                SQLToken t = this .lexer.getNextToken(true, false);
1484:                SQLToken last = previous;
1485:
1486:                while (t != null) {
1487:                    String text = t.getContents();
1488:                    if (t.getContents().equals("(")) {
1489:                        return this .processCommaList(t, 5, 7);
1490:                    } else if (t.isReservedWord() && "ON".equals(text)) {
1491:                        this .appendNewline();
1492:                        this .indent("       ");
1493:                        this .appendText(text);
1494:                    } else {
1495:                        if (this .needsWhitespace(last, t))
1496:                            this .appendText(' ');
1497:                        this .appendText(text);
1498:                    }
1499:                    t = this .lexer.getNextToken(true, false);
1500:                }
1501:                return t;
1502:            }
1503:
1504:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.