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 | */ |
6 | package org.h2.jdbc; |
7 | |
8 | import java.io.PrintStream; |
9 | import java.io.PrintWriter; |
10 | import java.sql.SQLException; |
11 | |
12 | import org.h2.engine.Constants; |
13 | |
14 | /** |
15 | * Represents a database exception. |
16 | */ |
17 | public class JdbcSQLException extends SQLException { |
18 | |
19 | /** |
20 | * If the SQL statement contains this text, then it is never added to the |
21 | * SQL exception. Hiding the SQL statement may be important if it contains a |
22 | * passwords, such as a CREATE LINKED TABLE statement. |
23 | */ |
24 | public static final String HIDE_SQL = "--hide--"; |
25 | |
26 | private static final long serialVersionUID = 1L; |
27 | private final String originalMessage; |
28 | private final Throwable cause; |
29 | private final String stackTrace; |
30 | private String message; |
31 | private String sql; |
32 | |
33 | /** |
34 | * Creates a SQLException. |
35 | * |
36 | * @param message the reason |
37 | * @param sql the SQL statement |
38 | * @param state the SQL state |
39 | * @param errorCode the error code |
40 | * @param cause the exception that was the reason for this exception |
41 | * @param stackTrace the stack trace |
42 | */ |
43 | public JdbcSQLException(String message, String sql, String state, |
44 | int errorCode, Throwable cause, String stackTrace) { |
45 | super(message, state, errorCode); |
46 | this.originalMessage = message; |
47 | setSQL(sql); |
48 | this.cause = cause; |
49 | this.stackTrace = stackTrace; |
50 | buildMessage(); |
51 | initCause(cause); |
52 | } |
53 | |
54 | /** |
55 | * Get the detail error message. |
56 | * |
57 | * @return the message |
58 | */ |
59 | @Override |
60 | public String getMessage() { |
61 | return message; |
62 | } |
63 | |
64 | /** |
65 | * INTERNAL |
66 | */ |
67 | public String getOriginalMessage() { |
68 | return originalMessage; |
69 | } |
70 | |
71 | /** |
72 | * Prints the stack trace to the standard error stream. |
73 | */ |
74 | @Override |
75 | public void printStackTrace() { |
76 | // The default implementation already does that, |
77 | // but we do it again to avoid problems. |
78 | // If it is not implemented, somebody might implement it |
79 | // later on which would be a problem if done in the wrong way. |
80 | printStackTrace(System.err); |
81 | } |
82 | |
83 | /** |
84 | * Prints the stack trace to the specified print writer. |
85 | * |
86 | * @param s the print writer |
87 | */ |
88 | @Override |
89 | public void printStackTrace(PrintWriter s) { |
90 | if (s != null) { |
91 | super.printStackTrace(s); |
92 | // getNextException().printStackTrace(s) would be very very slow |
93 | // if many exceptions are joined |
94 | SQLException next = getNextException(); |
95 | for (int i = 0; i < 100 && next != null; i++) { |
96 | s.println(next.toString()); |
97 | next = next.getNextException(); |
98 | } |
99 | if (next != null) { |
100 | s.println("(truncated)"); |
101 | } |
102 | } |
103 | } |
104 | |
105 | /** |
106 | * Prints the stack trace to the specified print stream. |
107 | * |
108 | * @param s the print stream |
109 | */ |
110 | @Override |
111 | public void printStackTrace(PrintStream s) { |
112 | if (s != null) { |
113 | super.printStackTrace(s); |
114 | // getNextException().printStackTrace(s) would be very very slow |
115 | // if many exceptions are joined |
116 | SQLException next = getNextException(); |
117 | for (int i = 0; i < 100 && next != null; i++) { |
118 | s.println(next.toString()); |
119 | next = next.getNextException(); |
120 | } |
121 | if (next != null) { |
122 | s.println("(truncated)"); |
123 | } |
124 | } |
125 | } |
126 | |
127 | /** |
128 | * INTERNAL |
129 | */ |
130 | public Throwable getOriginalCause() { |
131 | return cause; |
132 | } |
133 | |
134 | /** |
135 | * Returns the SQL statement. |
136 | * SQL statements that contain '--hide--' are not listed. |
137 | * |
138 | * @return the SQL statement |
139 | */ |
140 | public String getSQL() { |
141 | return sql; |
142 | } |
143 | |
144 | /** |
145 | * INTERNAL |
146 | */ |
147 | public void setSQL(String sql) { |
148 | if (sql != null && sql.contains(HIDE_SQL)) { |
149 | sql = "-"; |
150 | } |
151 | this.sql = sql; |
152 | buildMessage(); |
153 | } |
154 | |
155 | private void buildMessage() { |
156 | StringBuilder buff = new StringBuilder(originalMessage == null ? |
157 | "- " : originalMessage); |
158 | if (sql != null) { |
159 | buff.append("; SQL statement:\n").append(sql); |
160 | } |
161 | buff.append(" [").append(getErrorCode()). |
162 | append('-').append(Constants.BUILD_ID).append(']'); |
163 | message = buff.toString(); |
164 | } |
165 | |
166 | /** |
167 | * Returns the class name, the message, and in the server mode, the stack |
168 | * trace of the server |
169 | * |
170 | * @return the string representation |
171 | */ |
172 | @Override |
173 | public String toString() { |
174 | if (stackTrace == null) { |
175 | return super.toString(); |
176 | } |
177 | return stackTrace; |
178 | } |
179 | |
180 | } |