1 /* Copyright (c) 2001-2016, The HSQL Development Group 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of the HSQL Development Group nor the names of its 15 * contributors may be used to endorse or promote products derived from this 16 * software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, 22 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 32 package org.hsqldb.error; 33 34 import java.lang.reflect.Field; 35 36 import org.hsqldb.HsqlException; 37 import org.hsqldb.lib.StringUtil; 38 import org.hsqldb.resources.ResourceBundleHandler; 39 import org.hsqldb.result.Result; 40 41 /** 42 * Contains static factory methods to produce instances of HsqlException 43 * 44 * @author Loic Lefevre 45 * @author Fred Toussi (fredt@users dot sourceforge.net) 46 * @version 2.2.7 47 * @since 1.9.0 48 */ 49 public class Error { 50 51 // 52 public static boolean TRACE = false; 53 public static boolean TRACESYSTEMOUT = false; 54 55 // 56 private static final String defaultMessage = "S1000 General error"; 57 private static final String errPropsName = "sql-state-messages"; 58 private static final int bundleHandle = 59 ResourceBundleHandler.getBundleHandle(errPropsName, null); 60 private static final String MESSAGE_TAG = "$$"; 61 private static final int SQL_STATE_DIGITS = 5; 62 private static final int SQL_CODE_DIGITS = 4; 63 private static final int ERROR_CODE_BASE = 11; 64 runtimeError(int code, String add)65 public static RuntimeException runtimeError(int code, String add) { 66 67 HsqlException e = error(code, add); 68 69 return new RuntimeException(e.getMessage()); 70 } 71 error(int code, String add)72 public static HsqlException error(int code, String add) { 73 return error((Throwable) null, code, add); 74 } 75 error(Throwable t, int code, String add)76 public static HsqlException error(Throwable t, int code, String add) { 77 78 String s = getMessage(code); 79 80 if (add != null) { 81 s += ": " + add; 82 } 83 84 return new HsqlException(t, s.substring(SQL_STATE_DIGITS + 1), 85 s.substring(0, SQL_STATE_DIGITS), -code); 86 } 87 parseError(int code, String add, int lineNumber)88 public static HsqlException parseError(int code, String add, 89 int lineNumber) { 90 91 String s = getMessage(code); 92 93 if (add != null) { 94 s = s + ": " + add; 95 } 96 97 if (lineNumber > 1) { 98 add = getMessage(ErrorCode.M_parse_line); 99 s = s + " :" + add + String.valueOf(lineNumber); 100 } 101 102 return new HsqlException(null, s.substring(SQL_STATE_DIGITS + 1), 103 s.substring(0, SQL_STATE_DIGITS), -code); 104 } 105 error(int code)106 public static HsqlException error(int code) { 107 return error(null, code, 0, null); 108 } 109 error(int code, Throwable t)110 public static HsqlException error(int code, Throwable t) { 111 112 String message = getMessage(code, 0, null); 113 114 return new HsqlException(t, message.substring(0, SQL_STATE_DIGITS), 115 -code); 116 } 117 118 /** 119 * Compose error message by inserting the strings in the add parameters 120 * in placeholders within the error message. The message string contains 121 * $$ markers for each context variable. Context variables are supplied in 122 * the add parameters. 123 * 124 * @param code main error code 125 * @param subCode sub error code (if 0 => no subMessage!) 126 * @param add optional parameters 127 * 128 * @return an <code>HsqlException</code> 129 */ error(Throwable t, int code, int subCode, final Object[] add)130 public static HsqlException error(Throwable t, int code, int subCode, 131 final Object[] add) { 132 133 String message = getMessage(code, subCode, add); 134 int sqlCode = subCode < ERROR_CODE_BASE ? code 135 : subCode; 136 137 return new HsqlException(t, message.substring(SQL_STATE_DIGITS + 1), 138 message.substring(0, SQL_STATE_DIGITS), 139 -sqlCode); 140 } 141 142 public static HsqlException parseError(int code, int subCode, 143 int lineNumber, 144 final Object[] add) { 145 146 String message = getMessage(code, subCode, add); 147 148 if (lineNumber > 1) { 149 String sub = getMessage(ErrorCode.M_parse_line); 150 151 message = message + " :" + sub + String.valueOf(lineNumber); 152 } 153 154 int sqlCode = subCode < ERROR_CODE_BASE ? code 155 : subCode; 156 157 return new HsqlException(null, 158 message.substring(SQL_STATE_DIGITS + 1), 159 message.substring(0, SQL_STATE_DIGITS), 160 -sqlCode); 161 } 162 163 public static HsqlException error(int code, int code2) { 164 return error(code, getMessage(code2)); 165 } 166 167 /** 168 * For SIGNAL and RESIGNAL 169 * @see HsqlException#HsqlException(Throwable,String, String, int) 170 * @return an <code>HsqlException</code> 171 */ 172 public static HsqlException error(String message, String sqlState) { 173 174 int code = getCode(sqlState); 175 176 if (code < 1000) { 177 code = ErrorCode.X_45000; 178 } 179 180 if (message == null) { 181 message = getMessage(code); 182 } 183 184 return new HsqlException(null, message, sqlState, code); 185 } 186 187 /** 188 * Compose error message by inserting the strings in the add variables 189 * in placeholders within the error message. The message string contains 190 * $$ markers for each context variable. Context variables are supplied in 191 * the add parameter. (by Loic Lefevre) 192 * 193 * @param message message string 194 * @param add optional parameters 195 * 196 * @return an <code>HsqlException</code> 197 */ 198 private static String insertStrings(String message, Object[] add) { 199 200 StringBuffer sb = new StringBuffer(message.length() + 32); 201 int lastIndex = 0; 202 int escIndex = message.length(); 203 204 // removed test: i < add.length 205 // because if mainErrorMessage is equal to "blabla $$" 206 // then the statement escIndex = mainErrorMessage.length(); 207 // is never reached! ??? 208 for (int i = 0; i < add.length; i++) { 209 escIndex = message.indexOf(MESSAGE_TAG, lastIndex); 210 211 if (escIndex == -1) { 212 break; 213 } 214 215 sb.append(message.substring(lastIndex, escIndex)); 216 sb.append(add[i] == null ? "null exception message" 217 : add[i].toString()); 218 219 lastIndex = escIndex + MESSAGE_TAG.length(); 220 } 221 222 escIndex = message.length(); 223 224 sb.append(message.substring(lastIndex, escIndex)); 225 226 return sb.toString(); 227 } 228 229 /** 230 * Returns the error message given the error code.<br/> 231 * This method is be used when throwing exception other 232 * than <code>HsqlException</code>. 233 * 234 * @param errorCode the error code associated to the error message 235 * @return the error message associated with the error code 236 */ 237 public static String getMessage(final int errorCode) { 238 return getMessage(errorCode, 0, null); 239 } 240 241 /** 242 * Returns the error SQL STATE sting given the error code.<br/> 243 * This method is be used when throwing exception based on other exceptions. 244 * 245 * @param errorCode the error code associated to the error message 246 * @return the error message associated with the error code 247 */ 248 public static String getStateString(final int errorCode) { 249 return getMessage(errorCode, 0, null).substring(0, SQL_STATE_DIGITS); 250 } 251 252 /** 253 * Returns the error message given the error code.<br/> This method is used 254 * when throwing exception other than <code>HsqlException</code>. 255 * 256 * @param code the code for the error message 257 * @param subCode the code for the addon message 258 * @param add value(s) to use to replace the placeholer(s) 259 * @return the error message associated with the error code 260 */ 261 public static String getMessage(final int code, int subCode, 262 final Object[] add) { 263 264 String message = getResourceString(code); 265 266 if (subCode != 0) { 267 message += getResourceString(subCode); 268 } 269 270 if (add != null) { 271 message = insertStrings(message, add); 272 } 273 274 return message; 275 } 276 277 private static String getResourceString(int code) { 278 279 String key = StringUtil.toZeroPaddedString(code, SQL_CODE_DIGITS, 280 SQL_CODE_DIGITS); 281 String string = ResourceBundleHandler.getString(bundleHandle, key); 282 283 if (string == null) { 284 string = defaultMessage; 285 } 286 287 return string; 288 } 289 290 public static HsqlException error(final Result result) { 291 return new HsqlException(result); 292 } 293 294 /** 295 * Used to print messages to System.out 296 * 297 * 298 * @param message message to print 299 */ 300 public static void printSystemOut(String message) { 301 302 if (TRACESYSTEMOUT) { 303 System.out.println(message); 304 } 305 } 306 307 public static int getCode(String sqlState) { 308 309 try { 310 Field[] fields = ErrorCode.class.getDeclaredFields(); 311 312 for (int i = 0; i < fields.length; i++) { 313 String name = fields[i].getName(); 314 315 if (name.length() == 7 && name.endsWith(sqlState)) { 316 return fields[i].getInt(ErrorCode.class); 317 } 318 } 319 } catch (IllegalAccessException e) {} 320 321 return -1; 322 } 323 } 324