EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.server.web]

COVERAGE SUMMARY FOR SOURCE FILE [WebApp.java]

nameclass, %method, %block, %line, %
WebApp.java100% (4/4)96%  (53/55)88%  (5351/6082)87%  (955.2/1102)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class WebApp100% (1/1)98%  (47/48)88%  (5270/5997)87%  (946.2/1092)
adminStartTranslate (): String 0%   (0/1)0%   (0/23)0%   (0/5)
adminSave (): String 100% (1/1)12%  (8/69)20%  (3/15)
unescapeData (String, ResultSet, int): void 100% (1/1)29%  (33/112)25%  (9/36)
getLoginError (Exception, boolean): String 100% (1/1)52%  (14/27)67%  (2/3)
addDatabaseMetaData (SimpleResultSet, DatabaseMetaData): void 100% (1/1)58%  (63/109)63%  (7.6/12)
query (): String 100% (1/1)61%  (78/127)62%  (16/26)
isBinary (int): boolean 100% (1/1)67%  (4/6)67%  (2/3)
tools (): String 100% (1/1)78%  (125/161)77%  (30/39)
escapeData (ResultSet, int): String 100% (1/1)78%  (76/97)92%  (12/13)
test (): String 100% (1/1)82%  (127/155)94%  (29.2/31)
executeLoop (Connection, int, String): String 100% (1/1)82%  (246/300)82%  (46/56)
editResult (): String 100% (1/1)85%  (132/156)86%  (24/28)
autoCompleteList (): String 100% (1/1)85%  (265/313)87%  (58/67)
addIndexes (boolean, DatabaseMetaData, String, String, StringBuilder, int): int 100% (1/1)86%  (195/226)85%  (36.6/43)
getMaxrows (): int 100% (1/1)87%  (13/15)95%  (2.9/3)
login (): String 100% (1/1)87%  (74/85)83%  (15/18)
tables (): String 100% (1/1)89%  (322/362)90%  (56.5/63)
process (String): String 100% (1/1)89%  (146/164)87%  (34/39)
logout (): String 100% (1/1)90%  (43/48)87%  (13/15)
getMetaResultSet (Connection, String): ResultSet 100% (1/1)92%  (683/742)93%  (97/104)
getStackTrace (int, Throwable, boolean): String 100% (1/1)93%  (108/116)86%  (18/21)
addTablesAndViews (DbSchema, boolean, StringBuilder, int): int 100% (1/1)94%  (347/370)94%  (53.4/57)
index (): String 100% (1/1)95%  (129/136)93%  (26/28)
linkToSource (String): String 100% (1/1)96%  (151/158)94%  (33/35)
getResult (Connection, int, String, boolean, boolean): String 100% (1/1)96%  (567/591)96%  (109/114)
getParameterResultSet (ParameterMetaData): String 100% (1/1)98%  (81/83)88%  (7/8)
processRequest (String, String): String 100% (1/1)98%  (125/127)97%  (29/30)
addColumns (boolean, DbTableOrView, StringBuilder, int, boolean, StringBuilde... 100% (1/1)99%  (90/91)100% (14/14)
getResultSet (String, ResultSet, boolean, boolean, boolean, long, boolean): S... 100% (1/1)99%  (588/591)97%  (88/91)
WebApp (WebServer): void 100% (1/1)100% (6/6)100% (3/3)
admin (): String 100% (1/1)100% (45/45)100% (5/5)
adminShutdown (): String 100% (1/1)100% (5/5)100% (2/2)
escapeIdentifier (String): String 100% (1/1)100% (7/7)100% (1/1)
formatAsError (String): String 100% (1/1)100% (11/11)100% (1/1)
getCache (): boolean 100% (1/1)100% (3/3)100% (1/1)
getComboBox (String [], String): String 100% (1/1)100% (49/49)100% (7/7)
getComboBox (String [][], String): String 100% (1/1)100% (55/55)100% (7/7)
getCommandHistoryString (): String 100% (1/1)100% (54/54)100% (8/8)
getHistory (): String 100% (1/1)100% (19/19)100% (4/4)
getMimeType (): String 100% (1/1)100% (3/3)100% (1/1)
getSession (): WebSession 100% (1/1)100% (3/3)100% (1/1)
isBuiltIn (String, String): boolean 100% (1/1)100% (4/4)100% (1/1)
query (Connection, String, int, int, StringBuilder): void 100% (1/1)100% (46/46)100% (5/5)
setSession (WebSession, Properties): void 100% (1/1)100% (7/7)100% (3/3)
settingRemove (): String 100% (1/1)100% (31/31)100% (7/7)
settingSave (): String 100% (1/1)100% (49/49)100% (9/9)
split (String): String [] 100% (1/1)100% (35/35)100% (7/7)
trace (String): void 100% (1/1)100% (5/5)100% (2/2)
     
class WebApp$1100% (1/1)75%  (3/4)95%  (69/73)89%  (8/9)
remove (): void 0%   (0/1)0%   (0/4)0%   (0/1)
WebApp$1 (WebApp, ArrayList, Connection): void 100% (1/1)100% (12/12)100% (1/1)
hasNext (): boolean 100% (1/1)100% (10/10)100% (1/1)
next (): String 100% (1/1)100% (47/47)100% (6/6)
     
class WebApp$2100% (1/1)100% (2/2)100% (9/9)100% (2/2)
WebApp$2 (): void 100% (1/1)100% (3/3)100% (1/1)
compare (Method, Method): int 100% (1/1)100% (6/6)100% (1/1)
     
class WebApp$IndexInfo100% (1/1)100% (1/1)100% (3/3)100% (1/1)
WebApp$IndexInfo (): void 100% (1/1)100% (3/3)100% (1/1)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.server.web;
7 
8import java.io.ByteArrayOutputStream;
9import java.io.PrintStream;
10import java.io.PrintWriter;
11import java.io.StringReader;
12import java.io.StringWriter;
13import java.lang.reflect.InvocationTargetException;
14import java.lang.reflect.Method;
15import java.math.BigDecimal;
16import java.sql.Connection;
17import java.sql.DatabaseMetaData;
18import java.sql.ParameterMetaData;
19import java.sql.PreparedStatement;
20import java.sql.ResultSet;
21import java.sql.ResultSetMetaData;
22import java.sql.SQLException;
23import java.sql.Statement;
24import java.sql.Types;
25import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.Collections;
28import java.util.Comparator;
29import java.util.HashMap;
30import java.util.Iterator;
31import java.util.Locale;
32import java.util.Map;
33import java.util.Properties;
34import java.util.Random;
35 
36import org.h2.api.ErrorCode;
37import org.h2.bnf.Bnf;
38import org.h2.bnf.context.DbColumn;
39import org.h2.bnf.context.DbContents;
40import org.h2.bnf.context.DbSchema;
41import org.h2.bnf.context.DbTableOrView;
42import org.h2.engine.Constants;
43import org.h2.engine.SysProperties;
44import org.h2.jdbc.JdbcSQLException;
45import org.h2.message.DbException;
46import org.h2.security.SHA256;
47import org.h2.tools.Backup;
48import org.h2.tools.ChangeFileEncryption;
49import org.h2.tools.ConvertTraceFile;
50import org.h2.tools.CreateCluster;
51import org.h2.tools.DeleteDbFiles;
52import org.h2.tools.Recover;
53import org.h2.tools.Restore;
54import org.h2.tools.RunScript;
55import org.h2.tools.Script;
56import org.h2.tools.SimpleResultSet;
57import org.h2.util.JdbcUtils;
58import org.h2.util.New;
59import org.h2.util.Profiler;
60import org.h2.util.ScriptReader;
61import org.h2.util.SortedProperties;
62import org.h2.util.StatementBuilder;
63import org.h2.util.StringUtils;
64import org.h2.util.Tool;
65import org.h2.util.Utils;
66 
67/**
68 * For each connection to a session, an object of this class is created.
69 * This class is used by the H2 Console.
70 */
71public class WebApp {
72 
73    /**
74     * The web server.
75     */
76    protected final WebServer server;
77 
78    /**
79     * The session.
80     */
81    protected WebSession session;
82 
83    /**
84     * The session attributes
85     */
86    protected Properties attributes;
87 
88    /**
89     * The mime type of the current response.
90     */
91    protected String mimeType;
92 
93    /**
94     * Whether the response can be cached.
95     */
96    protected boolean cache;
97 
98    /**
99     * Whether to close the connection.
100     */
101    protected boolean stop;
102 
103    /**
104     * The language in the HTTP header.
105     */
106    protected String headerLanguage;
107 
108    private Profiler profiler;
109 
110    WebApp(WebServer server) {
111        this.server = server;
112    }
113 
114    /**
115     * Set the web session and attributes.
116     *
117     * @param session the session
118     * @param attributes the attributes
119     */
120    void setSession(WebSession session, Properties attributes) {
121        this.session = session;
122        this.attributes = attributes;
123    }
124 
125    /**
126     * Process an HTTP request.
127     *
128     * @param file the file that was requested
129     * @param hostAddr the host address
130     * @return the name of the file to return to the client
131     */
132    String processRequest(String file, String hostAddr) {
133        int index = file.lastIndexOf('.');
134        String suffix;
135        if (index >= 0) {
136            suffix = file.substring(index + 1);
137        } else {
138            suffix = "";
139        }
140        if ("ico".equals(suffix)) {
141            mimeType = "image/x-icon";
142            cache = true;
143        } else if ("gif".equals(suffix)) {
144            mimeType = "image/gif";
145            cache = true;
146        } else if ("css".equals(suffix)) {
147            cache = true;
148            mimeType = "text/css";
149        } else if ("html".equals(suffix) ||
150                "do".equals(suffix) ||
151                "jsp".equals(suffix)) {
152            cache = false;
153            mimeType = "text/html";
154            if (session == null && !file.startsWith(WebServer.TRANSFER)) {
155                session = server.createNewSession(hostAddr);
156                if (!"notAllowed.jsp".equals(file)) {
157                    file = "index.do";
158                }
159            }
160        } else if ("js".equals(suffix)) {
161            cache = true;
162            mimeType = "text/javascript";
163        } else {
164            cache = true;
165            mimeType = "application/octet-stream";
166        }
167        trace("mimeType=" + mimeType);
168        trace(file);
169        if (file.endsWith(".do")) {
170            file = process(file);
171        }
172        return file;
173    }
174 
175    private static String getComboBox(String[] elements, String selected) {
176        StringBuilder buff = new StringBuilder();
177        for (String value : elements) {
178            buff.append("<option value=\"").
179                append(PageParser.escapeHtmlData(value)).
180                append('\"');
181            if (value.equals(selected)) {
182                buff.append(" selected");
183            }
184            buff.append('>').
185                append(PageParser.escapeHtml(value)).
186                append("</option>");
187        }
188        return buff.toString();
189    }
190 
191    private static String getComboBox(String[][] elements, String selected) {
192        StringBuilder buff = new StringBuilder();
193        for (String[] n : elements) {
194            buff.append("<option value=\"").
195                append(PageParser.escapeHtmlData(n[0])).
196                append('\"');
197            if (n[0].equals(selected)) {
198                buff.append(" selected");
199            }
200            buff.append('>').
201                append(PageParser.escapeHtml(n[1])).
202                append("</option>");
203        }
204        return buff.toString();
205    }
206 
207    private String process(String file) {
208        trace("process " + file);
209        while (file.endsWith(".do")) {
210            if ("login.do".equals(file)) {
211                file = login();
212            } else if ("index.do".equals(file)) {
213                file = index();
214            } else if ("logout.do".equals(file)) {
215                file = logout();
216            } else if ("settingRemove.do".equals(file)) {
217                file = settingRemove();
218            } else if ("settingSave.do".equals(file)) {
219                file = settingSave();
220            } else if ("test.do".equals(file)) {
221                file = test();
222            } else if ("query.do".equals(file)) {
223                file = query();
224            } else if ("tables.do".equals(file)) {
225                file = tables();
226            } else if ("editResult.do".equals(file)) {
227                file = editResult();
228            } else if ("getHistory.do".equals(file)) {
229                file = getHistory();
230            } else if ("admin.do".equals(file)) {
231                file = admin();
232            } else if ("adminSave.do".equals(file)) {
233                file = adminSave();
234            } else if ("adminStartTranslate.do".equals(file)) {
235                file = adminStartTranslate();
236            } else if ("adminShutdown.do".equals(file)) {
237                file = adminShutdown();
238            } else if ("autoCompleteList.do".equals(file)) {
239                file = autoCompleteList();
240            } else if ("tools.do".equals(file)) {
241                file = tools();
242            } else if ("transfer.do".equals(file)) {
243                file = "transfer.jsp";
244            } else {
245                file = "error.jsp";
246            }
247        }
248        trace("return " + file);
249        return file;
250    }
251 
252    private String autoCompleteList() {
253        String query = (String) attributes.get("query");
254        boolean lowercase = false;
255        if (query.trim().length() > 0 &&
256                Character.isLowerCase(query.trim().charAt(0))) {
257            lowercase = true;
258        }
259        try {
260            String sql = query;
261            if (sql.endsWith(";")) {
262                sql += " ";
263            }
264            ScriptReader reader = new ScriptReader(new StringReader(sql));
265            reader.setSkipRemarks(true);
266            String lastSql = "";
267            while (true) {
268                String n = reader.readStatement();
269                if (n == null) {
270                    break;
271                }
272                lastSql = n;
273            }
274            String result = "";
275            if (reader.isInsideRemark()) {
276                if (reader.isBlockRemark()) {
277                    result = "1#(End Remark)# */\n" + result;
278                } else {
279                    result = "1#(Newline)#\n" + result;
280                }
281            } else {
282                sql = lastSql;
283                while (sql.length() > 0 && sql.charAt(0) <= ' ') {
284                    sql = sql.substring(1);
285                }
286                if (sql.trim().length() > 0 && Character.isLowerCase(sql.trim().charAt(0))) {
287                    lowercase = true;
288                }
289                Bnf bnf = session.getBnf();
290                if (bnf == null) {
291                    return "autoCompleteList.jsp";
292                }
293                HashMap<String, String> map = bnf.getNextTokenList(sql);
294                String space = "";
295                if (sql.length() > 0) {
296                    char last = sql.charAt(sql.length() - 1);
297                    if (!Character.isWhitespace(last) && (last != '.' &&
298                            last >= ' ' && last != '\'' && last != '"')) {
299                        space = " ";
300                    }
301                }
302                ArrayList<String> list = New.arrayList(map.size());
303                for (Map.Entry<String, String> entry : map.entrySet()) {
304                    String key = entry.getKey();
305                    String value = entry.getValue();
306                    String type = "" + key.charAt(0);
307                    if (Integer.parseInt(type) > 2) {
308                        continue;
309                    }
310                    key = key.substring(2);
311                    if (Character.isLetter(key.charAt(0)) && lowercase) {
312                        key = StringUtils.toLowerEnglish(key);
313                        value = StringUtils.toLowerEnglish(value);
314                    }
315                    if (key.equals(value) && !".".equals(value)) {
316                        value = space + value;
317                    }
318                    key = StringUtils.urlEncode(key);
319                    key = StringUtils.replaceAll(key, "+", " ");
320                    value = StringUtils.urlEncode(value);
321                    value = StringUtils.replaceAll(value, "+", " ");
322                    list.add(type + "#" + key + "#" + value);
323                }
324                Collections.sort(list);
325                if (query.endsWith("\n") || query.trim().endsWith(";")) {
326                    list.add(0, "1#(Newline)#\n");
327                }
328                StatementBuilder buff = new StatementBuilder();
329                for (String s : list) {
330                    buff.appendExceptFirst("|");
331                    buff.append(s);
332                }
333                result = buff.toString();
334            }
335            session.put("autoCompleteList", result);
336        } catch (Throwable e) {
337            server.traceError(e);
338        }
339        return "autoCompleteList.jsp";
340    }
341 
342    private String admin() {
343        session.put("port", "" + server.getPort());
344        session.put("allowOthers", "" + server.getAllowOthers());
345        session.put("ssl", String.valueOf(server.getSSL()));
346        session.put("sessions", server.getSessions());
347        return "admin.jsp";
348    }
349 
350    private String adminSave() {
351        try {
352            Properties prop = new SortedProperties();
353            int port = Integer.decode((String) attributes.get("port"));
354            prop.setProperty("webPort", String.valueOf(port));
355            server.setPort(port);
356            boolean allowOthers = Boolean.parseBoolean(
357                    (String) attributes.get("allowOthers"));
358            prop.setProperty("webAllowOthers", String.valueOf(allowOthers));
359            server.setAllowOthers(allowOthers);
360            boolean ssl = Boolean.parseBoolean(
361                    (String) attributes.get("ssl"));
362            prop.setProperty("webSSL", String.valueOf(ssl));
363            server.setSSL(ssl);
364            server.saveProperties(prop);
365        } catch (Exception e) {
366            trace(e.toString());
367        }
368        return admin();
369    }
370 
371    private String tools() {
372        try {
373            String toolName = (String) attributes.get("tool");
374            session.put("tool", toolName);
375            String args = (String) attributes.get("args");
376            String[] argList = StringUtils.arraySplit(args, ',', false);
377            Tool tool = null;
378            if ("Backup".equals(toolName)) {
379                tool = new Backup();
380            } else if ("Restore".equals(toolName)) {
381                tool = new Restore();
382            } else if ("Recover".equals(toolName)) {
383                tool = new Recover();
384            } else if ("DeleteDbFiles".equals(toolName)) {
385                tool = new DeleteDbFiles();
386            } else if ("ChangeFileEncryption".equals(toolName)) {
387                tool = new ChangeFileEncryption();
388            } else if ("Script".equals(toolName)) {
389                tool = new Script();
390            } else if ("RunScript".equals(toolName)) {
391                tool = new RunScript();
392            } else if ("ConvertTraceFile".equals(toolName)) {
393                tool = new ConvertTraceFile();
394            } else if ("CreateCluster".equals(toolName)) {
395                tool = new CreateCluster();
396            } else {
397                throw DbException.throwInternalError(toolName);
398            }
399            ByteArrayOutputStream outBuff = new ByteArrayOutputStream();
400            PrintStream out = new PrintStream(outBuff, false, "UTF-8");
401            tool.setOut(out);
402            try {
403                tool.runTool(argList);
404                out.flush();
405                String o = new String(outBuff.toByteArray(), Constants.UTF8);
406                String result = PageParser.escapeHtml(o);
407                session.put("toolResult", result);
408            } catch (Exception e) {
409                session.put("toolResult", getStackTrace(0, e, true));
410            }
411        } catch (Exception e) {
412            server.traceError(e);
413        }
414        return "tools.jsp";
415    }
416 
417    private String adminStartTranslate() {
418        Map<?, ?> p = Map.class.cast(session.map.get("text"));
419        @SuppressWarnings("unchecked")
420        Map<Object, Object> p2 = (Map<Object, Object>) p;
421        String file = server.startTranslate(p2);
422        session.put("translationFile", file);
423        return "helpTranslate.jsp";
424    }
425 
426    /**
427     * Stop the application and the server.
428     *
429     * @return the page to display
430     */
431    protected String adminShutdown() {
432        server.shutdown();
433        return "admin.jsp";
434    }
435 
436    private String index() {
437        String[][] languageArray = WebServer.LANGUAGES;
438        String language = (String) attributes.get("language");
439        Locale locale = session.locale;
440        if (language != null) {
441            if (locale == null || !StringUtils.toLowerEnglish(
442                    locale.getLanguage()).equals(language)) {
443                locale = new Locale(language, "");
444                server.readTranslations(session, locale.getLanguage());
445                session.put("language", language);
446                session.locale = locale;
447            }
448        } else {
449            language = (String) session.get("language");
450        }
451        if (language == null) {
452            // if the language is not yet known
453            // use the last header
454            language = headerLanguage;
455        }
456        session.put("languageCombo", getComboBox(languageArray, language));
457        String[] settingNames = server.getSettingNames();
458        String setting = attributes.getProperty("setting");
459        if (setting == null && settingNames.length > 0) {
460            setting = settingNames[0];
461        }
462        String combobox = getComboBox(settingNames, setting);
463        session.put("settingsList", combobox);
464        ConnectionInfo info = server.getSetting(setting);
465        if (info == null) {
466            info = new ConnectionInfo();
467        }
468        session.put("setting", PageParser.escapeHtmlData(setting));
469        session.put("name", PageParser.escapeHtmlData(setting));
470        session.put("driver", PageParser.escapeHtmlData(info.driver));
471        session.put("url", PageParser.escapeHtmlData(info.url));
472        session.put("user", PageParser.escapeHtmlData(info.user));
473        return "index.jsp";
474    }
475 
476    private String getHistory() {
477        int id = Integer.parseInt(attributes.getProperty("id"));
478        String sql = session.getCommand(id);
479        session.put("query", PageParser.escapeHtmlData(sql));
480        return "query.jsp";
481    }
482 
483    private static int addColumns(boolean mainSchema, DbTableOrView table,
484            StringBuilder buff, int treeIndex, boolean showColumnTypes,
485            StringBuilder columnsBuffer) {
486        DbColumn[] columns = table.getColumns();
487        for (int i = 0; columns != null && i < columns.length; i++) {
488            DbColumn column = columns[i];
489            if (columnsBuffer.length() > 0) {
490                columnsBuffer.append(' ');
491            }
492            columnsBuffer.append(column.getName());
493            String col = escapeIdentifier(column.getName());
494            String level = mainSchema ? ", 1, 1" : ", 2, 2";
495            buff.append("setNode(" + treeIndex + level + ", 'column', '" +
496                    PageParser.escapeJavaScript(column.getName()) +
497                    "', 'javascript:ins(\\'" + col + "\\')');\n");
498            treeIndex++;
499            if (mainSchema && showColumnTypes) {
500                buff.append("setNode(" + treeIndex + ", 2, 2, 'type', '" +
501                        PageParser.escapeJavaScript(column.getDataType()) +
502                        "', null);\n");
503                treeIndex++;
504            }
505        }
506        return treeIndex;
507    }
508 
509    private static String escapeIdentifier(String name) {
510        return StringUtils.urlEncode(
511                PageParser.escapeJavaScript(name)).replace('+', ' ');
512    }
513 
514    /**
515     * This class represents index information for the GUI.
516     */
517    static class IndexInfo {
518 
519        /**
520         * The index name.
521         */
522        String name;
523 
524        /**
525         * The index type name.
526         */
527        String type;
528 
529        /**
530         * The indexed columns.
531         */
532        String columns;
533    }
534 
535    private static int addIndexes(boolean mainSchema, DatabaseMetaData meta,
536            String table, String schema, StringBuilder buff, int treeIndex)
537            throws SQLException {
538        ResultSet rs;
539        try {
540            rs = meta.getIndexInfo(null, schema, table, false, true);
541        } catch (SQLException e) {
542            // SQLite
543            return treeIndex;
544        }
545        HashMap<String, IndexInfo> indexMap = New.hashMap();
546        while (rs.next()) {
547            String name = rs.getString("INDEX_NAME");
548            IndexInfo info = indexMap.get(name);
549            if (info == null) {
550                int t = rs.getInt("TYPE");
551                String type;
552                if (t == DatabaseMetaData.tableIndexClustered) {
553                    type = "";
554                } else if (t == DatabaseMetaData.tableIndexHashed) {
555                    type = " (${text.tree.hashed})";
556                } else if (t == DatabaseMetaData.tableIndexOther) {
557                    type = "";
558                } else {
559                    type = null;
560                }
561                if (name != null && type != null) {
562                    info = new IndexInfo();
563                    info.name = name;
564                    type = (rs.getBoolean("NON_UNIQUE") ?
565                            "${text.tree.nonUnique}" : "${text.tree.unique}") + type;
566                    info.type = type;
567                    info.columns = rs.getString("COLUMN_NAME");
568                    indexMap.put(name, info);
569                }
570            } else {
571                info.columns += ", " + rs.getString("COLUMN_NAME");
572            }
573        }
574        rs.close();
575        if (indexMap.size() > 0) {
576            String level = mainSchema ? ", 1, 1" : ", 2, 1";
577            String levelIndex = mainSchema ? ", 2, 1" : ", 3, 1";
578            String levelColumnType = mainSchema ? ", 3, 2" : ", 4, 2";
579            buff.append("setNode(" + treeIndex + level +
580                    ", 'index_az', '${text.tree.indexes}', null);\n");
581            treeIndex++;
582            for (IndexInfo info : indexMap.values()) {
583                buff.append("setNode(" + treeIndex + levelIndex +
584                        ", 'index', '" +
585                        PageParser.escapeJavaScript(info.name) + "', null);\n");
586                treeIndex++;
587                buff.append("setNode(" + treeIndex + levelColumnType +
588                        ", 'type', '" + info.type + "', null);\n");
589                treeIndex++;
590                buff.append("setNode(" + treeIndex + levelColumnType +
591                        ", 'type', '" +
592                        PageParser.escapeJavaScript(info.columns) +
593                        "', null);\n");
594                treeIndex++;
595            }
596        }
597        return treeIndex;
598    }
599 
600    private int addTablesAndViews(DbSchema schema, boolean mainSchema,
601            StringBuilder buff, int treeIndex) throws SQLException {
602        if (schema == null) {
603            return treeIndex;
604        }
605        Connection conn = session.getConnection();
606        DatabaseMetaData meta = session.getMetaData();
607        int level = mainSchema ? 0 : 1;
608        boolean showColumns = mainSchema || !schema.isSystem;
609        String indentation = ", " + level + ", " + (showColumns ? "1" : "2") + ", ";
610        String indentNode = ", " + (level + 1) + ", 2, ";
611        DbTableOrView[] tables = schema.getTables();
612        if (tables == null) {
613            return treeIndex;
614        }
615        boolean isOracle = schema.getContents().isOracle();
616        boolean notManyTables = tables.length < SysProperties.CONSOLE_MAX_TABLES_LIST_INDEXES;
617        for (DbTableOrView table : tables) {
618            if (table.isView()) {
619                continue;
620            }
621            int tableId = treeIndex;
622            String tab = table.getQuotedName();
623            if (!mainSchema) {
624                tab = schema.quotedName + "." + tab;
625            }
626            tab = escapeIdentifier(tab);
627            buff.append("setNode(" + treeIndex + indentation + " 'table', '" +
628                    PageParser.escapeJavaScript(table.getName()) +
629                    "', 'javascript:ins(\\'" + tab + "\\',true)');\n");
630            treeIndex++;
631            if (mainSchema || showColumns) {
632                StringBuilder columnsBuffer = new StringBuilder();
633                treeIndex = addColumns(mainSchema, table, buff, treeIndex,
634                        notManyTables, columnsBuffer);
635                if (!isOracle && notManyTables) {
636                    treeIndex = addIndexes(mainSchema, meta, table.getName(),
637                            schema.name, buff, treeIndex);
638                }
639                buff.append("addTable('" +
640                        PageParser.escapeJavaScript(table.getName()) + "', '" +
641                        PageParser.escapeJavaScript(columnsBuffer.toString()) +
642                        "', " + tableId + ");\n");
643            }
644        }
645        tables = schema.getTables();
646        for (DbTableOrView view : tables) {
647            if (!view.isView()) {
648                continue;
649            }
650            int tableId = treeIndex;
651            String tab = view.getQuotedName();
652            if (!mainSchema) {
653                tab = view.getSchema().quotedName + "." + tab;
654            }
655            tab = escapeIdentifier(tab);
656            buff.append("setNode(" + treeIndex + indentation + " 'view', '" +
657                    PageParser.escapeJavaScript(view.getName()) +
658                    "', 'javascript:ins(\\'" + tab + "\\',true)');\n");
659            treeIndex++;
660            if (mainSchema) {
661                StringBuilder columnsBuffer = new StringBuilder();
662                treeIndex = addColumns(mainSchema, view, buff,
663                        treeIndex, notManyTables, columnsBuffer);
664                if (schema.getContents().isH2()) {
665                    PreparedStatement prep = null;
666                    try {
667                        prep = conn.prepareStatement("SELECT * FROM " +
668                                "INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=?");
669                        prep.setString(1, view.getName());
670                        ResultSet rs = prep.executeQuery();
671                        if (rs.next()) {
672                            String sql = rs.getString("SQL");
673                            buff.append("setNode(" + treeIndex + indentNode +
674                                    " 'type', '" +
675                                    PageParser.escapeJavaScript(sql) +
676                                    "', null);\n");
677                            treeIndex++;
678                        }
679                        rs.close();
680                    } finally {
681                        JdbcUtils.closeSilently(prep);
682                    }
683                }
684                buff.append("addTable('" +
685                        PageParser.escapeJavaScript(view.getName()) + "', '" +
686                        PageParser.escapeJavaScript(columnsBuffer.toString()) +
687                        "', " + tableId + ");\n");
688            }
689        }
690        return treeIndex;
691    }
692 
693    private String tables() {
694        DbContents contents = session.getContents();
695        boolean isH2 = false;
696        try {
697            String url = (String) session.get("url");
698            Connection conn = session.getConnection();
699            contents.readContents(url, conn);
700            session.loadBnf();
701            isH2 = contents.isH2();
702 
703            StringBuilder buff = new StringBuilder();
704            buff.append("setNode(0, 0, 0, 'database', '" + PageParser.escapeJavaScript(url)
705                    + "', null);\n");
706            int treeIndex = 1;
707 
708            DbSchema defaultSchema = contents.getDefaultSchema();
709            treeIndex = addTablesAndViews(defaultSchema, true, buff, treeIndex);
710            DbSchema[] schemas = contents.getSchemas();
711            for (DbSchema schema : schemas) {
712                if (schema == defaultSchema || schema == null) {
713                    continue;
714                }
715                buff.append("setNode(" + treeIndex + ", 0, 1, 'folder', '" +
716                        PageParser.escapeJavaScript(schema.name) +
717                        "', null);\n");
718                treeIndex++;
719                treeIndex = addTablesAndViews(schema, false, buff, treeIndex);
720            }
721            if (isH2) {
722                Statement stat = null;
723                try {
724                    stat = conn.createStatement();
725                    ResultSet rs = stat.executeQuery("SELECT * FROM " +
726                            "INFORMATION_SCHEMA.SEQUENCES ORDER BY SEQUENCE_NAME");
727                    for (int i = 0; rs.next(); i++) {
728                        if (i == 0) {
729                            buff.append("setNode(" + treeIndex +
730                                    ", 0, 1, 'sequences', '${text.tree.sequences}', null);\n");
731                            treeIndex++;
732                        }
733                        String name = rs.getString("SEQUENCE_NAME");
734                        String current = rs.getString("CURRENT_VALUE");
735                        String increment = rs.getString("INCREMENT");
736                        buff.append("setNode(" + treeIndex +
737                                ", 1, 1, 'sequence', '" +
738                                PageParser.escapeJavaScript(name) +
739                                "', null);\n");
740                        treeIndex++;
741                        buff.append("setNode(" + treeIndex +
742                                ", 2, 2, 'type', '${text.tree.current}: " +
743                                PageParser.escapeJavaScript(current) +
744                                "', null);\n");
745                        treeIndex++;
746                        if (!"1".equals(increment)) {
747                            buff.append("setNode(" +
748                                    treeIndex +
749                                    ", 2, 2, 'type', '${text.tree.increment}: " +
750                                    PageParser.escapeJavaScript(increment) +
751                                    "', null);\n");
752                            treeIndex++;
753                        }
754                    }
755                    rs.close();
756                    rs = stat.executeQuery("SELECT * FROM " +
757                            "INFORMATION_SCHEMA.USERS ORDER BY NAME");
758                    for (int i = 0; rs.next(); i++) {
759                        if (i == 0) {
760                            buff.append("setNode(" + treeIndex +
761                                    ", 0, 1, 'users', '${text.tree.users}', null);\n");
762                            treeIndex++;
763                        }
764                        String name = rs.getString("NAME");
765                        String admin = rs.getString("ADMIN");
766                        buff.append("setNode(" + treeIndex +
767                                ", 1, 1, 'user', '" +
768                                PageParser.escapeJavaScript(name) +
769                                "', null);\n");
770                        treeIndex++;
771                        if (admin.equalsIgnoreCase("TRUE")) {
772                            buff.append("setNode(" + treeIndex +
773                                    ", 2, 2, 'type', '${text.tree.admin}', null);\n");
774                            treeIndex++;
775                        }
776                    }
777                    rs.close();
778                } finally {
779                    JdbcUtils.closeSilently(stat);
780                }
781            }
782            DatabaseMetaData meta = session.getMetaData();
783            String version = meta.getDatabaseProductName() + " " +
784                    meta.getDatabaseProductVersion();
785            buff.append("setNode(" + treeIndex + ", 0, 0, 'info', '" +
786                    PageParser.escapeJavaScript(version) + "', null);\n");
787            buff.append("refreshQueryTables();");
788            session.put("tree", buff.toString());
789        } catch (Exception e) {
790            session.put("tree", "");
791            session.put("error", getStackTrace(0, e, isH2));
792        }
793        return "tables.jsp";
794    }
795 
796    private String getStackTrace(int id, Throwable e, boolean isH2) {
797        try {
798            StringWriter writer = new StringWriter();
799            e.printStackTrace(new PrintWriter(writer));
800            String stackTrace = writer.toString();
801            stackTrace = PageParser.escapeHtml(stackTrace);
802            if (isH2) {
803                stackTrace = linkToSource(stackTrace);
804            }
805            stackTrace = StringUtils.replaceAll(stackTrace, "\t",
806                    "&nbsp;&nbsp;&nbsp;&nbsp;");
807            String message = PageParser.escapeHtml(e.getMessage());
808            String error = "<a class=\"error\" href=\"#\" " +
809                    "onclick=\"var x=document.getElementById('st" + id +
810                    "').style;x.display=x.display==''?'none':'';\">" + message +
811                    "</a>";
812            if (e instanceof SQLException) {
813                SQLException se = (SQLException) e;
814                error += " " + se.getSQLState() + "/" + se.getErrorCode();
815                if (isH2) {
816                    int code = se.getErrorCode();
817                    error += " <a href=\"http://h2database.com/javadoc/" +
818                            "org/h2/constant/ErrorCode.html#c" + code +
819                            "\">(${text.a.help})</a>";
820                }
821            }
822            error += "<span style=\"display: none;\" id=\"st" + id +
823                    "\"><br />" + stackTrace + "</span>";
824            error = formatAsError(error);
825            return error;
826        } catch (OutOfMemoryError e2) {
827            server.traceError(e);
828            return e.toString();
829        }
830    }
831 
832    private static String linkToSource(String s) {
833        try {
834            StringBuilder result = new StringBuilder(s.length());
835            int idx = s.indexOf("<br />");
836            result.append(s.substring(0, idx));
837            while (true) {
838                int start = s.indexOf("org.h2.", idx);
839                if (start < 0) {
840                    result.append(s.substring(idx));
841                    break;
842                }
843                result.append(s.substring(idx, start));
844                int end = s.indexOf(')', start);
845                if (end < 0) {
846                    result.append(s.substring(idx));
847                    break;
848                }
849                String element = s.substring(start, end);
850                int open = element.lastIndexOf('(');
851                int dotMethod = element.lastIndexOf('.', open - 1);
852                int dotClass = element.lastIndexOf('.', dotMethod - 1);
853                String packageName = element.substring(0, dotClass);
854                int colon = element.lastIndexOf(':');
855                String file = element.substring(open + 1, colon);
856                String lineNumber = element.substring(colon + 1, element.length());
857                String fullFileName = packageName.replace('.', '/') + "/" + file;
858                result.append("<a href=\"http://h2database.com/html/source.html?file=");
859                result.append(fullFileName);
860                result.append("&line=");
861                result.append(lineNumber);
862                result.append("&build=");
863                result.append(Constants.BUILD_ID);
864                result.append("\">");
865                result.append(element);
866                result.append("</a>");
867                idx = end;
868            }
869            return result.toString();
870        } catch (Throwable t) {
871            return s;
872        }
873    }
874 
875    private static String formatAsError(String s) {
876        return "<div class=\"error\">" + s + "</div>";
877    }
878 
879    private String test() {
880        String driver = attributes.getProperty("driver", "");
881        String url = attributes.getProperty("url", "");
882        String user = attributes.getProperty("user", "");
883        String password = attributes.getProperty("password", "");
884        session.put("driver", driver);
885        session.put("url", url);
886        session.put("user", user);
887        boolean isH2 = url.startsWith("jdbc:h2:");
888        try {
889            long start = System.currentTimeMillis();
890            String profOpen = "", profClose = "";
891            Profiler prof = new Profiler();
892            prof.startCollecting();
893            Connection conn;
894            try {
895                conn = server.getConnection(driver, url, user, password);
896            } finally {
897                prof.stopCollecting();
898                profOpen = prof.getTop(3);
899            }
900            prof = new Profiler();
901            prof.startCollecting();
902            try {
903                JdbcUtils.closeSilently(conn);
904            } finally {
905                prof.stopCollecting();
906                profClose = prof.getTop(3);
907            }
908            long time = System.currentTimeMillis() - start;
909            String success;
910            if (time > 1000) {
911                success = "<a class=\"error\" href=\"#\" " +
912                    "onclick=\"var x=document.getElementById('prof').style;x." +
913                    "display=x.display==''?'none':'';\">" +
914                    "${text.login.testSuccessful}</a>" +
915                    "<span style=\"display: none;\" id=\"prof\"><br />" +
916                    PageParser.escapeHtml(profOpen) +
917                    "<br />" +
918                    PageParser.escapeHtml(profClose) +
919                    "</span>";
920            } else {
921                success = "${text.login.testSuccessful}";
922            }
923            session.put("error", success);
924            // session.put("error", "${text.login.testSuccessful}");
925            return "login.jsp";
926        } catch (Exception e) {
927            session.put("error", getLoginError(e, isH2));
928            return "login.jsp";
929        }
930    }
931 
932    /**
933     * Get the formatted login error message.
934     *
935     * @param e the exception
936     * @param isH2 if the current database is a H2 database
937     * @return the formatted error message
938     */
939    private String getLoginError(Exception e, boolean isH2) {
940        if (e instanceof JdbcSQLException &&
941                ((JdbcSQLException) e).getErrorCode() == ErrorCode.CLASS_NOT_FOUND_1) {
942            return "${text.login.driverNotFound}<br />" + getStackTrace(0, e, isH2);
943        }
944        return getStackTrace(0, e, isH2);
945    }
946 
947    private String login() {
948        String driver = attributes.getProperty("driver", "");
949        String url = attributes.getProperty("url", "");
950        String user = attributes.getProperty("user", "");
951        String password = attributes.getProperty("password", "");
952        session.put("autoCommit", "checked");
953        session.put("autoComplete", "1");
954        session.put("maxrows", "1000");
955        boolean isH2 = url.startsWith("jdbc:h2:");
956        try {
957            Connection conn = server.getConnection(driver, url, user, password);
958            session.setConnection(conn);
959            session.put("url", url);
960            session.put("user", user);
961            session.remove("error");
962            settingSave();
963            return "frame.jsp";
964        } catch (Exception e) {
965            session.put("error", getLoginError(e, isH2));
966            return "login.jsp";
967        }
968    }
969 
970    private String logout() {
971        try {
972            Connection conn = session.getConnection();
973            session.setConnection(null);
974            session.remove("conn");
975            session.remove("result");
976            session.remove("tables");
977            session.remove("user");
978            session.remove("tool");
979            if (conn != null) {
980                if (session.getShutdownServerOnDisconnect()) {
981                    server.shutdown();
982                } else {
983                    conn.close();
984                }
985            }
986        } catch (Exception e) {
987            trace(e.toString());
988        }
989        return "index.do";
990    }
991 
992    private String query() {
993        String sql = attributes.getProperty("sql").trim();
994        try {
995            ScriptReader r = new ScriptReader(new StringReader(sql));
996            final ArrayList<String> list = New.arrayList();
997            while (true) {
998                String s = r.readStatement();
999                if (s == null) {
1000                    break;
1001                }
1002                list.add(s);
1003            }
1004            final Connection conn = session.getConnection();
1005            if (SysProperties.CONSOLE_STREAM && server.getAllowChunked()) {
1006                String page = new String(server.getFile("result.jsp"), Constants.UTF8);
1007                int idx = page.indexOf("${result}");
1008                // the first element of the list is the header, the last the
1009                // footer
1010                list.add(0, page.substring(0, idx));
1011                list.add(page.substring(idx + "${result}".length()));
1012                session.put("chunks", new Iterator<String>() {
1013                    private int i;
1014                    @Override
1015                    public boolean hasNext() {
1016                        return i < list.size();
1017                    }
1018                    @Override
1019                    public String next() {
1020                        String s = list.get(i++);
1021                        if (i == 1 || i == list.size()) {
1022                            return s;
1023                        }
1024                        StringBuilder b = new StringBuilder();
1025                        query(conn, s, i - 1, list.size() - 2, b);
1026                        return b.toString();
1027                    }
1028                    @Override
1029                    public void remove() {
1030                        throw new UnsupportedOperationException();
1031                    }
1032                });
1033                return "result.jsp";
1034            }
1035            String result;
1036            StringBuilder buff = new StringBuilder();
1037            for (int i = 0; i < list.size(); i++) {
1038                String s = list.get(i);
1039                query(conn, s, i, list.size(), buff);
1040            }
1041            result = buff.toString();
1042            session.put("result", result);
1043        } catch (Throwable e) {
1044            session.put("result", getStackTrace(0, e, session.getContents().isH2()));
1045        }
1046        return "result.jsp";
1047    }
1048 
1049    /**
1050     * Execute a query and append the result to the buffer.
1051     *
1052     * @param conn the connection
1053     * @param s the statement
1054     * @param i the index
1055     * @param size the number of statements
1056     * @param buff the target buffer
1057     */
1058    void query(Connection conn, String s, int i, int size, StringBuilder buff) {
1059        if (!(s.startsWith("@") && s.endsWith("."))) {
1060            buff.append(PageParser.escapeHtml(s + ";")).append("<br />");
1061        }
1062        boolean forceEdit = s.startsWith("@edit");
1063        buff.append(getResult(conn, i + 1, s, size == 1, forceEdit)).
1064            append("<br />");
1065    }
1066 
1067    private String editResult() {
1068        ResultSet rs = session.result;
1069        int row = Integer.parseInt(attributes.getProperty("row"));
1070        int op = Integer.parseInt(attributes.getProperty("op"));
1071        String result = "", error = "";
1072        try {
1073            if (op == 1) {
1074                boolean insert = row < 0;
1075                if (insert) {
1076                    rs.moveToInsertRow();
1077                } else {
1078                    rs.absolute(row);
1079                }
1080                for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
1081                    String x = attributes.getProperty("r" + row + "c" + (i + 1));
1082                    unescapeData(x, rs, i + 1);
1083                }
1084                if (insert) {
1085                    rs.insertRow();
1086                } else {
1087                    rs.updateRow();
1088                }
1089            } else if (op == 2) {
1090                rs.absolute(row);
1091                rs.deleteRow();
1092            } else if (op == 3) {
1093                // cancel
1094            }
1095        } catch (Throwable e) {
1096            result = "<br />" + getStackTrace(0, e, session.getContents().isH2());
1097            error = formatAsError(e.getMessage());
1098        }
1099        String sql = "@edit " + (String) session.get("resultSetSQL");
1100        Connection conn = session.getConnection();
1101        result = error + getResult(conn, -1, sql, true, true) + result;
1102        session.put("result", result);
1103        return "result.jsp";
1104    }
1105 
1106    private ResultSet getMetaResultSet(Connection conn, String sql)
1107            throws SQLException {
1108        DatabaseMetaData meta = conn.getMetaData();
1109        if (isBuiltIn(sql, "@best_row_identifier")) {
1110            String[] p = split(sql);
1111            int scale = p[4] == null ? 0 : Integer.parseInt(p[4]);
1112            boolean nullable = p[5] == null ? false : Boolean.parseBoolean(p[5]);
1113            return meta.getBestRowIdentifier(p[1], p[2], p[3], scale, nullable);
1114        } else if (isBuiltIn(sql, "@catalogs")) {
1115            return meta.getCatalogs();
1116        } else if (isBuiltIn(sql, "@columns")) {
1117            String[] p = split(sql);
1118            return meta.getColumns(p[1], p[2], p[3], p[4]);
1119        } else if (isBuiltIn(sql, "@column_privileges")) {
1120            String[] p = split(sql);
1121            return meta.getColumnPrivileges(p[1], p[2], p[3], p[4]);
1122        } else if (isBuiltIn(sql, "@cross_references")) {
1123            String[] p = split(sql);
1124            return meta.getCrossReference(p[1], p[2], p[3], p[4], p[5], p[6]);
1125        } else if (isBuiltIn(sql, "@exported_keys")) {
1126            String[] p = split(sql);
1127            return meta.getExportedKeys(p[1], p[2], p[3]);
1128        } else if (isBuiltIn(sql, "@imported_keys")) {
1129            String[] p = split(sql);
1130            return meta.getImportedKeys(p[1], p[2], p[3]);
1131        } else if (isBuiltIn(sql, "@index_info")) {
1132            String[] p = split(sql);
1133            boolean unique = p[4] == null ? false : Boolean.parseBoolean(p[4]);
1134            boolean approx = p[5] == null ? false : Boolean.parseBoolean(p[5]);
1135            return meta.getIndexInfo(p[1], p[2], p[3], unique, approx);
1136        } else if (isBuiltIn(sql, "@primary_keys")) {
1137            String[] p = split(sql);
1138            return meta.getPrimaryKeys(p[1], p[2], p[3]);
1139        } else if (isBuiltIn(sql, "@procedures")) {
1140            String[] p = split(sql);
1141            return meta.getProcedures(p[1], p[2], p[3]);
1142        } else if (isBuiltIn(sql, "@procedure_columns")) {
1143            String[] p = split(sql);
1144            return meta.getProcedureColumns(p[1], p[2], p[3], p[4]);
1145        } else if (isBuiltIn(sql, "@schemas")) {
1146            return meta.getSchemas();
1147        } else if (isBuiltIn(sql, "@tables")) {
1148            String[] p = split(sql);
1149            String[] types = p[4] == null ? null : StringUtils.arraySplit(p[4], ',', false);
1150            return meta.getTables(p[1], p[2], p[3], types);
1151        } else if (isBuiltIn(sql, "@table_privileges")) {
1152            String[] p = split(sql);
1153            return meta.getTablePrivileges(p[1], p[2], p[3]);
1154        } else if (isBuiltIn(sql, "@table_types")) {
1155            return meta.getTableTypes();
1156        } else if (isBuiltIn(sql, "@type_info")) {
1157            return meta.getTypeInfo();
1158        } else if (isBuiltIn(sql, "@udts")) {
1159            String[] p = split(sql);
1160            int[] types;
1161            if (p[4] == null) {
1162                types = null;
1163            } else {
1164                String[] t = StringUtils.arraySplit(p[4], ',', false);
1165                types = new int[t.length];
1166                for (int i = 0; i < t.length; i++) {
1167                    types[i] = Integer.parseInt(t[i]);
1168                }
1169            }
1170            return meta.getUDTs(p[1], p[2], p[3], types);
1171        } else if (isBuiltIn(sql, "@version_columns")) {
1172            String[] p = split(sql);
1173            return meta.getVersionColumns(p[1], p[2], p[3]);
1174        } else if (isBuiltIn(sql, "@memory")) {
1175            SimpleResultSet rs = new SimpleResultSet();
1176            rs.addColumn("Type", Types.VARCHAR, 0, 0);
1177            rs.addColumn("KB", Types.VARCHAR, 0, 0);
1178            rs.addRow("Used Memory", "" + Utils.getMemoryUsed());
1179            rs.addRow("Free Memory", "" + Utils.getMemoryFree());
1180            return rs;
1181        } else if (isBuiltIn(sql, "@info")) {
1182            SimpleResultSet rs = new SimpleResultSet();
1183            rs.addColumn("KEY", Types.VARCHAR, 0, 0);
1184            rs.addColumn("VALUE", Types.VARCHAR, 0, 0);
1185            rs.addRow("conn.getCatalog", conn.getCatalog());
1186            rs.addRow("conn.getAutoCommit", "" + conn.getAutoCommit());
1187            rs.addRow("conn.getTransactionIsolation", "" + conn.getTransactionIsolation());
1188            rs.addRow("conn.getWarnings", "" + conn.getWarnings());
1189            String map;
1190            try {
1191                map = "" + conn.getTypeMap();
1192            } catch (SQLException e) {
1193                map = e.toString();
1194            }
1195            rs.addRow("conn.getTypeMap", "" + map);
1196            rs.addRow("conn.isReadOnly", "" + conn.isReadOnly());
1197            rs.addRow("conn.getHoldability", "" + conn.getHoldability());
1198            addDatabaseMetaData(rs, meta);
1199            return rs;
1200        } else if (isBuiltIn(sql, "@attributes")) {
1201            String[] p = split(sql);
1202            return meta.getAttributes(p[1], p[2], p[3], p[4]);
1203        } else if (isBuiltIn(sql, "@super_tables")) {
1204            String[] p = split(sql);
1205            return meta.getSuperTables(p[1], p[2], p[3]);
1206        } else if (isBuiltIn(sql, "@super_types")) {
1207            String[] p = split(sql);
1208            return meta.getSuperTypes(p[1], p[2], p[3]);
1209        } else if (isBuiltIn(sql, "@prof_stop")) {
1210            if (profiler != null) {
1211                profiler.stopCollecting();
1212                SimpleResultSet rs = new SimpleResultSet();
1213                rs.addColumn("Top Stack Trace(s)", Types.VARCHAR, 0, 0);
1214                rs.addRow(profiler.getTop(3));
1215                profiler = null;
1216                return rs;
1217            }
1218        }
1219        return null;
1220    }
1221 
1222    private static void addDatabaseMetaData(SimpleResultSet rs,
1223            DatabaseMetaData meta) {
1224        Method[] methods = DatabaseMetaData.class.getDeclaredMethods();
1225        Arrays.sort(methods, new Comparator<Method>() {
1226            @Override
1227            public int compare(Method o1, Method o2) {
1228                return o1.toString().compareTo(o2.toString());
1229            }
1230        });
1231        for (Method m : methods) {
1232            if (m.getParameterTypes().length == 0) {
1233                try {
1234                    Object o = m.invoke(meta);
1235                    rs.addRow("meta." + m.getName(), "" + o);
1236                } catch (InvocationTargetException e) {
1237                    rs.addRow("meta." + m.getName(), e.getTargetException().toString());
1238                } catch (Exception e) {
1239                    rs.addRow("meta." + m.getName(), e.toString());
1240                }
1241            }
1242        }
1243    }
1244 
1245    private static String[] split(String s) {
1246        String[] list = new String[10];
1247        String[] t = StringUtils.arraySplit(s, ' ', true);
1248        System.arraycopy(t, 0, list, 0, t.length);
1249        for (int i = 0; i < list.length; i++) {
1250            if ("null".equals(list[i])) {
1251                list[i] = null;
1252            }
1253        }
1254        return list;
1255    }
1256 
1257    private int getMaxrows() {
1258        String r = (String) session.get("maxrows");
1259        int maxrows = r == null ? 0 : Integer.parseInt(r);
1260        return maxrows;
1261    }
1262 
1263    private String getResult(Connection conn, int id, String sql,
1264            boolean allowEdit, boolean forceEdit) {
1265        try {
1266            sql = sql.trim();
1267            StringBuilder buff = new StringBuilder();
1268            String sqlUpper = StringUtils.toUpperEnglish(sql);
1269            if (sqlUpper.contains("CREATE") ||
1270                    sqlUpper.contains("DROP") ||
1271                    sqlUpper.contains("ALTER") ||
1272                    sqlUpper.contains("RUNSCRIPT")) {
1273                String sessionId = attributes.getProperty("jsessionid");
1274                buff.append("<script type=\"text/javascript\">" +
1275                        "parent['h2menu'].location='tables.do?jsessionid="
1276                        + sessionId + "';</script>");
1277            }
1278            Statement stat;
1279            DbContents contents = session.getContents();
1280            if (forceEdit || (allowEdit && contents.isH2())) {
1281                stat = conn.createStatement(
1282                        ResultSet.TYPE_SCROLL_INSENSITIVE,
1283                        ResultSet.CONCUR_UPDATABLE);
1284            } else {
1285                stat = conn.createStatement();
1286            }
1287            ResultSet rs;
1288            long time = System.currentTimeMillis();
1289            boolean metadata = false;
1290            boolean generatedKeys = false;
1291            boolean edit = false;
1292            boolean list = false;
1293            if (isBuiltIn(sql, "@autocommit_true")) {
1294                conn.setAutoCommit(true);
1295                return "${text.result.autoCommitOn}";
1296            } else if (isBuiltIn(sql, "@autocommit_false")) {
1297                conn.setAutoCommit(false);
1298                return "${text.result.autoCommitOff}";
1299            } else if (isBuiltIn(sql, "@cancel")) {
1300                stat = session.executingStatement;
1301                if (stat != null) {
1302                    stat.cancel();
1303                    buff.append("${text.result.statementWasCanceled}");
1304                } else {
1305                    buff.append("${text.result.noRunningStatement}");
1306                }
1307                return buff.toString();
1308            } else if (isBuiltIn(sql, "@edit")) {
1309                edit = true;
1310                sql = sql.substring("@edit".length()).trim();
1311                session.put("resultSetSQL", sql);
1312            }
1313            if (isBuiltIn(sql, "@list")) {
1314                list = true;
1315                sql = sql.substring("@list".length()).trim();
1316            }
1317            if (isBuiltIn(sql, "@meta")) {
1318                metadata = true;
1319                sql = sql.substring("@meta".length()).trim();
1320            }
1321            if (isBuiltIn(sql, "@generated")) {
1322                generatedKeys = true;
1323                sql = sql.substring("@generated".length()).trim();
1324            } else if (isBuiltIn(sql, "@history")) {
1325                buff.append(getCommandHistoryString());
1326                return buff.toString();
1327            } else if (isBuiltIn(sql, "@loop")) {
1328                sql = sql.substring("@loop".length()).trim();
1329                int idx = sql.indexOf(' ');
1330                int count = Integer.decode(sql.substring(0, idx));
1331                sql = sql.substring(idx).trim();
1332                return executeLoop(conn, count, sql);
1333            } else if (isBuiltIn(sql, "@maxrows")) {
1334                int maxrows = (int) Double.parseDouble(
1335                        sql.substring("@maxrows".length()).trim());
1336                session.put("maxrows", "" + maxrows);
1337                return "${text.result.maxrowsSet}";
1338            } else if (isBuiltIn(sql, "@parameter_meta")) {
1339                sql = sql.substring("@parameter_meta".length()).trim();
1340                PreparedStatement prep = conn.prepareStatement(sql);
1341                buff.append(getParameterResultSet(prep.getParameterMetaData()));
1342                return buff.toString();
1343            } else if (isBuiltIn(sql, "@password_hash")) {
1344                sql = sql.substring("@password_hash".length()).trim();
1345                String[] p = split(sql);
1346                return StringUtils.convertBytesToHex(
1347                        SHA256.getKeyPasswordHash(p[0], p[1].toCharArray()));
1348            } else if (isBuiltIn(sql, "@prof_start")) {
1349                if (profiler != null) {
1350                    profiler.stopCollecting();
1351                }
1352                profiler = new Profiler();
1353                profiler.startCollecting();
1354                return "Ok";
1355            } else if (isBuiltIn(sql, "@sleep")) {
1356                String s = sql.substring("@sleep".length()).trim();
1357                int sleep = 1;
1358                if (s.length() > 0) {
1359                    sleep = Integer.parseInt(s);
1360                }
1361                Thread.sleep(sleep * 1000);
1362                return "Ok";
1363            } else if (isBuiltIn(sql, "@transaction_isolation")) {
1364                String s = sql.substring("@transaction_isolation".length()).trim();
1365                if (s.length() > 0) {
1366                    int level = Integer.parseInt(s);
1367                    conn.setTransactionIsolation(level);
1368                }
1369                buff.append("Transaction Isolation: " +
1370                        conn.getTransactionIsolation() + "<br />");
1371                buff.append(Connection.TRANSACTION_READ_UNCOMMITTED +
1372                        ": read_uncommitted<br />");
1373                buff.append(Connection.TRANSACTION_READ_COMMITTED +
1374                        ": read_committed<br />");
1375                buff.append(Connection.TRANSACTION_REPEATABLE_READ +
1376                        ": repeatable_read<br />");
1377                buff.append(Connection.TRANSACTION_SERIALIZABLE +
1378                        ": serializable");
1379            }
1380            if (sql.startsWith("@")) {
1381                rs = getMetaResultSet(conn, sql);
1382                if (rs == null) {
1383                    buff.append("?: " + sql);
1384                    return buff.toString();
1385                }
1386            } else {
1387                int maxrows = getMaxrows();
1388                stat.setMaxRows(maxrows);
1389                session.executingStatement = stat;
1390                boolean isResultSet = stat.execute(sql);
1391                session.addCommand(sql);
1392                if (generatedKeys) {
1393                    rs = null;
1394                    rs = stat.getGeneratedKeys();
1395                } else {
1396                    if (!isResultSet) {
1397                        buff.append("${text.result.updateCount}: " + stat.getUpdateCount());
1398                        time = System.currentTimeMillis() - time;
1399                        buff.append("<br />(").append(time).append(" ms)");
1400                        stat.close();
1401                        return buff.toString();
1402                    }
1403                    rs = stat.getResultSet();
1404                }
1405            }
1406            time = System.currentTimeMillis() - time;
1407            buff.append(getResultSet(sql, rs, metadata, list, edit, time, allowEdit));
1408            // SQLWarning warning = stat.getWarnings();
1409            // if (warning != null) {
1410            // buff.append("<br />Warning:<br />").
1411            // append(getStackTrace(id, warning));
1412            // }
1413            if (!edit) {
1414                stat.close();
1415            }
1416            return buff.toString();
1417        } catch (Throwable e) {
1418            // throwable: including OutOfMemoryError and so on
1419            return getStackTrace(id, e, session.getContents().isH2());
1420        } finally {
1421            session.executingStatement = null;
1422        }
1423    }
1424 
1425    private static boolean isBuiltIn(String sql, String builtIn) {
1426        return StringUtils.startsWithIgnoreCase(sql, builtIn);
1427    }
1428 
1429    private String executeLoop(Connection conn, int count, String sql)
1430            throws SQLException {
1431        ArrayList<Integer> params = New.arrayList();
1432        int idx = 0;
1433        while (!stop) {
1434            idx = sql.indexOf('?', idx);
1435            if (idx < 0) {
1436                break;
1437            }
1438            if (isBuiltIn(sql.substring(idx), "?/*rnd*/")) {
1439                params.add(1);
1440                sql = sql.substring(0, idx) + "?" + sql.substring(idx + "/*rnd*/".length() + 1);
1441            } else {
1442                params.add(0);
1443            }
1444            idx++;
1445        }
1446        boolean prepared;
1447        Random random = new Random(1);
1448        long time = System.currentTimeMillis();
1449        if (isBuiltIn(sql, "@statement")) {
1450            sql = sql.substring("@statement".length()).trim();
1451            prepared = false;
1452            Statement stat = conn.createStatement();
1453            for (int i = 0; !stop && i < count; i++) {
1454                String s = sql;
1455                for (Integer type : params) {
1456                    idx = s.indexOf('?');
1457                    if (type.intValue() == 1) {
1458                        s = s.substring(0, idx) + random.nextInt(count) + s.substring(idx + 1);
1459                    } else {
1460                        s = s.substring(0, idx) + i + s.substring(idx + 1);
1461                    }
1462                }
1463                if (stat.execute(s)) {
1464                    ResultSet rs = stat.getResultSet();
1465                    while (!stop && rs.next()) {
1466                        // maybe get the data as well
1467                    }
1468                    rs.close();
1469                }
1470            }
1471        } else {
1472            prepared = true;
1473            PreparedStatement prep = conn.prepareStatement(sql);
1474            for (int i = 0; !stop && i < count; i++) {
1475                for (int j = 0; j < params.size(); j++) {
1476                    Integer type = params.get(j);
1477                    if (type.intValue() == 1) {
1478                        prep.setInt(j + 1, random.nextInt(count));
1479                    } else {
1480                        prep.setInt(j + 1, i);
1481                    }
1482                }
1483                if (session.getContents().isSQLite()) {
1484                    // SQLite currently throws an exception on prep.execute()
1485                    prep.executeUpdate();
1486                } else {
1487                    if (prep.execute()) {
1488                        ResultSet rs = prep.getResultSet();
1489                        while (!stop && rs.next()) {
1490                            // maybe get the data as well
1491                        }
1492                        rs.close();
1493                    }
1494                }
1495            }
1496        }
1497        time = System.currentTimeMillis() - time;
1498        StatementBuilder buff = new StatementBuilder();
1499        buff.append(time).append(" ms: ").append(count).append(" * ");
1500        if (prepared) {
1501            buff.append("(Prepared) ");
1502        } else {
1503            buff.append("(Statement) ");
1504        }
1505        buff.append('(');
1506        for (int p : params) {
1507            buff.appendExceptFirst(", ");
1508            buff.append(p == 0 ? "i" : "rnd");
1509        }
1510        return buff.append(") ").append(sql).toString();
1511    }
1512 
1513    private String getCommandHistoryString() {
1514        StringBuilder buff = new StringBuilder();
1515        ArrayList<String> history = session.getCommandHistory();
1516        buff.append("<table cellspacing=0 cellpadding=0>" +
1517                "<tr><th></th><th>Command</th></tr>");
1518        for (int i = history.size() - 1; i >= 0; i--) {
1519            String sql = history.get(i);
1520            buff.append("<tr><td><a href=\"getHistory.do?id=").
1521                append(i).
1522                append("&jsessionid=${sessionId}\" target=\"h2query\" >").
1523                append("<img width=16 height=16 src=\"ico_write.gif\" " +
1524                        "onmouseover = \"this.className ='icon_hover'\" ").
1525                append("onmouseout = \"this.className ='icon'\" " +
1526                        "class=\"icon\" alt=\"${text.resultEdit.edit}\" ").
1527                append("title=\"${text.resultEdit.edit}\" border=\"1\"/></a>").
1528                append("</td><td>").
1529                append(PageParser.escapeHtml(sql)).
1530                append("</td></tr>");
1531        }
1532        buff.append("</table>");
1533        return buff.toString();
1534    }
1535 
1536    private static String getParameterResultSet(ParameterMetaData meta)
1537            throws SQLException {
1538        StringBuilder buff = new StringBuilder();
1539        if (meta == null) {
1540            return "No parameter meta data";
1541        }
1542        buff.append("<table cellspacing=0 cellpadding=0>").
1543            append("<tr><th>className</th><th>mode</th><th>type</th>").
1544            append("<th>typeName</th><th>precision</th><th>scale</th></tr>");
1545        for (int i = 0; i < meta.getParameterCount(); i++) {
1546            buff.append("</tr><td>").
1547                append(meta.getParameterClassName(i + 1)).
1548                append("</td><td>").
1549                append(meta.getParameterMode(i + 1)).
1550                append("</td><td>").
1551                append(meta.getParameterType(i + 1)).
1552                append("</td><td>").
1553                append(meta.getParameterTypeName(i + 1)).
1554                append("</td><td>").
1555                append(meta.getPrecision(i + 1)).
1556                append("</td><td>").
1557                append(meta.getScale(i + 1)).
1558                append("</td></tr>");
1559        }
1560        buff.append("</table>");
1561        return buff.toString();
1562    }
1563 
1564    private String getResultSet(String sql, ResultSet rs, boolean metadata,
1565            boolean list, boolean edit, long time, boolean allowEdit)
1566            throws SQLException {
1567        int maxrows = getMaxrows();
1568        time = System.currentTimeMillis() - time;
1569        StringBuilder buff = new StringBuilder();
1570        if (edit) {
1571            buff.append("<form id=\"editing\" name=\"editing\" method=\"post\" " +
1572                    "action=\"editResult.do?jsessionid=${sessionId}\" " +
1573                    "id=\"mainForm\" target=\"h2result\">" +
1574                    "<input type=\"hidden\" name=\"op\" value=\"1\" />" +
1575                    "<input type=\"hidden\" name=\"row\" value=\"\" />" +
1576                    "<table cellspacing=0 cellpadding=0 id=\"editTable\">");
1577        } else {
1578            buff.append("<table cellspacing=0 cellpadding=0>");
1579        }
1580        if (metadata) {
1581            SimpleResultSet r = new SimpleResultSet();
1582            r.addColumn("#", Types.INTEGER, 0, 0);
1583            r.addColumn("label", Types.VARCHAR, 0, 0);
1584            r.addColumn("catalog", Types.VARCHAR, 0, 0);
1585            r.addColumn("schema", Types.VARCHAR, 0, 0);
1586            r.addColumn("table", Types.VARCHAR, 0, 0);
1587            r.addColumn("column", Types.VARCHAR, 0, 0);
1588            r.addColumn("type", Types.INTEGER, 0, 0);
1589            r.addColumn("typeName", Types.VARCHAR, 0, 0);
1590            r.addColumn("class", Types.VARCHAR, 0, 0);
1591            r.addColumn("precision", Types.INTEGER, 0, 0);
1592            r.addColumn("scale", Types.INTEGER, 0, 0);
1593            r.addColumn("displaySize", Types.INTEGER, 0, 0);
1594            r.addColumn("autoIncrement", Types.BOOLEAN, 0, 0);
1595            r.addColumn("caseSensitive", Types.BOOLEAN, 0, 0);
1596            r.addColumn("currency", Types.BOOLEAN, 0, 0);
1597            r.addColumn("nullable", Types.INTEGER, 0, 0);
1598            r.addColumn("readOnly", Types.BOOLEAN, 0, 0);
1599            r.addColumn("searchable", Types.BOOLEAN, 0, 0);
1600            r.addColumn("signed", Types.BOOLEAN, 0, 0);
1601            r.addColumn("writable", Types.BOOLEAN, 0, 0);
1602            r.addColumn("definitelyWritable", Types.BOOLEAN, 0, 0);
1603            ResultSetMetaData m = rs.getMetaData();
1604            for (int i = 1; i <= m.getColumnCount(); i++) {
1605                r.addRow(i,
1606                        m.getColumnLabel(i),
1607                        m.getCatalogName(i),
1608                        m.getSchemaName(i),
1609                        m.getTableName(i),
1610                        m.getColumnName(i),
1611                        m.getColumnType(i),
1612                        m.getColumnTypeName(i),
1613                        m.getColumnClassName(i),
1614                        m.getPrecision(i),
1615                        m.getScale(i),
1616                        m.getColumnDisplaySize(i),
1617                        m.isAutoIncrement(i),
1618                        m.isCaseSensitive(i),
1619                        m.isCurrency(i),
1620                        m.isNullable(i),
1621                        m.isReadOnly(i),
1622                        m.isSearchable(i),
1623                        m.isSigned(i),
1624                        m.isWritable(i),
1625                        m.isDefinitelyWritable(i));
1626            }
1627            rs = r;
1628        }
1629        ResultSetMetaData meta = rs.getMetaData();
1630        int columns = meta.getColumnCount();
1631        int rows = 0;
1632        if (list) {
1633            buff.append("<tr><th>Column</th><th>Data</th></tr><tr>");
1634            while (rs.next()) {
1635                if (maxrows > 0 && rows >= maxrows) {
1636                    break;
1637                }
1638                rows++;
1639                buff.append("<tr><td>Row #</td><td>").
1640                    append(rows).append("</tr>");
1641                for (int i = 0; i < columns; i++) {
1642                    buff.append("<tr><td>").
1643                        append(PageParser.escapeHtml(meta.getColumnLabel(i + 1))).
1644                        append("</td><td>").
1645                        append(escapeData(rs, i + 1)).
1646                        append("</td></tr>");
1647                }
1648            }
1649        } else {
1650            buff.append("<tr>");
1651            if (edit) {
1652                buff.append("<th>${text.resultEdit.action}</th>");
1653            }
1654            for (int i = 0; i < columns; i++) {
1655                buff.append("<th>").
1656                    append(PageParser.escapeHtml(meta.getColumnLabel(i + 1))).
1657                    append("</th>");
1658            }
1659            buff.append("</tr>");
1660            while (rs.next()) {
1661                if (maxrows > 0 && rows >= maxrows) {
1662                    break;
1663                }
1664                rows++;
1665                buff.append("<tr>");
1666                if (edit) {
1667                    buff.append("<td>").
1668                        append("<img onclick=\"javascript:editRow(").
1669                        append(rs.getRow()).
1670                        append(",'${sessionId}', '${text.resultEdit.save}', " +
1671                                "'${text.resultEdit.cancel}'").
1672                        append(")\" width=16 height=16 src=\"ico_write.gif\" " +
1673                                "onmouseover = \"this.className ='icon_hover'\" " +
1674                                "onmouseout = \"this.className ='icon'\" " +
1675                                "class=\"icon\" alt=\"${text.resultEdit.edit}\" " +
1676                                "title=\"${text.resultEdit.edit}\" border=\"1\"/>").
1677                        append("<a href=\"editResult.do?op=2&row=").
1678                        append(rs.getRow()).
1679                        append("&jsessionid=${sessionId}\" target=\"h2result\" >" +
1680                                "<img width=16 height=16 src=\"ico_remove.gif\" " +
1681                                "onmouseover = \"this.className ='icon_hover'\" " +
1682                                "onmouseout = \"this.className ='icon'\" " +
1683                                "class=\"icon\" alt=\"${text.resultEdit.delete}\" " +
1684                                "title=\"${text.resultEdit.delete}\" border=\"1\" /></a>").
1685                        append("</td>");
1686                }
1687                for (int i = 0; i < columns; i++) {
1688                    buff.append("<td>").
1689                        append(escapeData(rs, i + 1)).
1690                        append("</td>");
1691                }
1692                buff.append("</tr>");
1693            }
1694        }
1695        boolean isUpdatable = false;
1696        try {
1697            isUpdatable = rs.getConcurrency() == ResultSet.CONCUR_UPDATABLE
1698                && rs.getType() != ResultSet.TYPE_FORWARD_ONLY;
1699        } catch (NullPointerException e) {
1700            // ignore
1701            // workaround for a JDBC-ODBC bridge problem
1702        }
1703        if (edit) {
1704            ResultSet old = session.result;
1705            if (old != null) {
1706                old.close();
1707            }
1708            session.result = rs;
1709        } else {
1710            rs.close();
1711        }
1712        if (edit) {
1713            buff.append("<tr><td>").
1714                append("<img onclick=\"javascript:editRow(-1, " +
1715                        "'${sessionId}', '${text.resultEdit.save}', '${text.resultEdit.cancel}'").
1716                append(")\" width=16 height=16 src=\"ico_add.gif\" " +
1717                        "onmouseover = \"this.className ='icon_hover'\" " +
1718                        "onmouseout = \"this.className ='icon'\" " +
1719                        "class=\"icon\" alt=\"${text.resultEdit.add}\" " +
1720                        "title=\"${text.resultEdit.add}\" border=\"1\"/>").
1721                append("</td>");
1722            for (int i = 0; i < columns; i++) {
1723                buff.append("<td></td>");
1724            }
1725            buff.append("</tr>");
1726        }
1727        buff.append("</table>");
1728        if (edit) {
1729            buff.append("</form>");
1730        }
1731        if (rows == 0) {
1732            buff.append("(${text.result.noRows}");
1733        } else if (rows == 1) {
1734            buff.append("(${text.result.1row}");
1735        } else {
1736            buff.append('(').append(rows).append(" ${text.result.rows}");
1737        }
1738        buff.append(", ");
1739        time = System.currentTimeMillis() - time;
1740        buff.append(time).append(" ms)");
1741        if (!edit && isUpdatable && allowEdit) {
1742            buff.append("<br /><br />" +
1743                    "<form name=\"editResult\" method=\"post\" " +
1744                    "action=\"query.do?jsessionid=${sessionId}\" target=\"h2result\">" +
1745                    "<input type=\"submit\" class=\"button\" " +
1746                    "value=\"${text.resultEdit.editResult}\" />" +
1747                    "<input type=\"hidden\" name=\"sql\" value=\"@edit ").
1748            append(PageParser.escapeHtmlData(sql)).
1749            append("\" /></form>");
1750        }
1751        return buff.toString();
1752    }
1753 
1754    /**
1755     * Save the current connection settings to the properties file.
1756     *
1757     * @return the file to open afterwards
1758     */
1759    private String settingSave() {
1760        ConnectionInfo info = new ConnectionInfo();
1761        info.name = attributes.getProperty("name", "");
1762        info.driver = attributes.getProperty("driver", "");
1763        info.url = attributes.getProperty("url", "");
1764        info.user = attributes.getProperty("user", "");
1765        server.updateSetting(info);
1766        attributes.put("setting", info.name);
1767        server.saveProperties(null);
1768        return "index.do";
1769    }
1770 
1771    private static String escapeData(ResultSet rs, int columnIndex)
1772            throws SQLException {
1773        String d = rs.getString(columnIndex);
1774        if (d == null) {
1775            return "<i>null</i>";
1776        } else if (d.length() > 100000) {
1777            String s;
1778            if (isBinary(rs.getMetaData().getColumnType(columnIndex))) {
1779                s = PageParser.escapeHtml(d.substring(0, 6)) +
1780                        "... (" + (d.length() / 2) + " ${text.result.bytes})";
1781            } else {
1782                s = PageParser.escapeHtml(d.substring(0, 100)) +
1783                        "... (" + d.length() + " ${text.result.characters})";
1784            }
1785            return "<div style='display: none'>=+</div>" + s;
1786        } else if (d.equals("null") || d.startsWith("= ") || d.startsWith("=+")) {
1787            return "<div style='display: none'>= </div>" + PageParser.escapeHtml(d);
1788        } else if (d.equals("")) {
1789            // PageParser.escapeHtml replaces "" with a non-breaking space
1790            return "";
1791        }
1792        return PageParser.escapeHtml(d);
1793    }
1794 
1795    private static boolean isBinary(int sqlType) {
1796        switch (sqlType) {
1797        case Types.BINARY:
1798        case Types.BLOB:
1799        case Types.JAVA_OBJECT:
1800        case Types.LONGVARBINARY:
1801        case Types.OTHER:
1802        case Types.VARBINARY:
1803            return true;
1804        }
1805        return false;
1806    }
1807 
1808    private void unescapeData(String x, ResultSet rs, int columnIndex)
1809            throws SQLException {
1810        if (x.equals("null")) {
1811            rs.updateNull(columnIndex);
1812            return;
1813        } else if (x.startsWith("=+")) {
1814            // don't update
1815            return;
1816        } else if (x.equals("=*")) {
1817            // set an appropriate default value
1818            int type = rs.getMetaData().getColumnType(columnIndex);
1819            switch (type) {
1820            case Types.TIME:
1821                rs.updateString(columnIndex, "12:00:00");
1822                break;
1823            case Types.TIMESTAMP:
1824            case Types.DATE:
1825                rs.updateString(columnIndex, "2001-01-01");
1826                break;
1827            default:
1828                rs.updateString(columnIndex, "1");
1829                break;
1830            }
1831            return;
1832        } else if (x.startsWith("= ")) {
1833            x = x.substring(2);
1834        }
1835        ResultSetMetaData meta = rs.getMetaData();
1836        int type = meta.getColumnType(columnIndex);
1837        if (session.getContents().isH2()) {
1838            rs.updateString(columnIndex, x);
1839            return;
1840        }
1841        switch (type) {
1842        case Types.BIGINT:
1843            rs.updateLong(columnIndex, Long.decode(x));
1844            break;
1845        case Types.DECIMAL:
1846            rs.updateBigDecimal(columnIndex, new BigDecimal(x));
1847            break;
1848        case Types.DOUBLE:
1849        case Types.FLOAT:
1850            rs.updateDouble(columnIndex, Double.parseDouble(x));
1851            break;
1852        case Types.REAL:
1853            rs.updateFloat(columnIndex, Float.parseFloat(x));
1854            break;
1855        case Types.INTEGER:
1856            rs.updateInt(columnIndex, Integer.decode(x));
1857            break;
1858        case Types.TINYINT:
1859            rs.updateShort(columnIndex, Short.decode(x));
1860            break;
1861        default:
1862            rs.updateString(columnIndex, x);
1863        }
1864    }
1865 
1866    private String settingRemove() {
1867        String setting = attributes.getProperty("name", "");
1868        server.removeSetting(setting);
1869        ArrayList<ConnectionInfo> settings = server.getSettings();
1870        if (settings.size() > 0) {
1871            attributes.put("setting", settings.get(0));
1872        }
1873        server.saveProperties(null);
1874        return "index.do";
1875    }
1876 
1877    /**
1878     * Get the current mime type.
1879     *
1880     * @return the mime type
1881     */
1882    String getMimeType() {
1883        return mimeType;
1884    }
1885 
1886    boolean getCache() {
1887        return cache;
1888    }
1889 
1890    WebSession getSession() {
1891        return session;
1892    }
1893 
1894    private void trace(String s) {
1895        server.trace(s);
1896    }
1897 
1898}

[all classes][org.h2.server.web]
EMMA 2.0.5312 (C) Vladimir Roubtsov