aboutsummaryrefslogtreecommitdiffstats
path: root/src/com/iciql/IciqlException.java
blob: 3f27b733ef33bdce57dc80fa288eea16ac655b0c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/*
 * Copyright 2011 James Moger.
 * Copyright 2012 Frédéric Gaillard
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iciql;

import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.regex.Pattern;

/**
 * Iciql wraps all exceptions with this class.
 */
public class IciqlException extends RuntimeException {

	public static final int CODE_UNMAPPED_FIELD = 1;
	public static final int CODE_DUPLICATE_KEY = 2;
	public static final int CODE_OBJECT_NOT_FOUND = 3;
	public static final int CODE_OBJECT_ALREADY_EXISTS = 4;
	public static final int CODE_CONSTRAINT_VIOLATION = 5;
	public static final int CODE_UNCHARACTERIZED = 6;

	private static final String TOKEN_UNMAPPED_FIELD = "\\? (=|\\>|\\<|\\<\\>|!=|\\>=|\\<=|LIKE|BETWEEN) \\?";

	private static final long serialVersionUID = 1L;

	private String sql;

	private int iciqlCode;

	public IciqlException(Throwable t) {
		super(t.getMessage(), t);
		configureCode(t);
	}

	public IciqlException(String message, Object... parameters) {
		super(parameters.length > 0 ? MessageFormat.format(message, parameters) : message);
	}

	public IciqlException(Throwable t, String message, Object... parameters) {
		super(parameters.length > 0 ? MessageFormat.format(message, parameters) : message, t);
		configureCode(t);
	}

	public static void checkUnmappedField(String sql) {
		if (Pattern.compile(IciqlException.TOKEN_UNMAPPED_FIELD).matcher(sql).find()) {
			IciqlException e = new IciqlException("unmapped field in statement!");
			e.sql = sql;
			e.iciqlCode = CODE_UNMAPPED_FIELD;
			throw e;
		}
	}

	public static IciqlException fromSQL(String sql, Throwable t) {
		if (Pattern.compile(TOKEN_UNMAPPED_FIELD).matcher(sql).find()) {
			IciqlException e = new IciqlException(t, "unmapped field in statement!");
			e.sql = sql;
			e.iciqlCode = CODE_UNMAPPED_FIELD;
			return e;
		} else {
			IciqlException e = new IciqlException(t, t.getMessage());
			e.sql = sql;
			return e;
		}
	}

	public void setSQL(String sql) {
		this.sql = sql;
	}

	public String getSQL() {
		return sql;
	}

	public int getIciqlCode() {
		return iciqlCode;
	}

	private void configureCode(Throwable t) {
		if (t == null) {
			return;
		}
		if (t instanceof SQLException) {
			// http://developer.mimer.com/documentation/html_92/Mimer_SQL_Mobile_DocSet/App_Return_Codes2.html
			SQLException s = (SQLException) t;
			String state = s.getSQLState();
			if ("23000".equals(state)) {
				// MySQL duplicate primary key on insert
				iciqlCode = CODE_DUPLICATE_KEY;
				if (s.getErrorCode() == 1217) {
					iciqlCode = CODE_CONSTRAINT_VIOLATION;	
				}
			} else if ("23505".equals(state)) {
				// Derby duplicate primary key on insert
				iciqlCode = CODE_DUPLICATE_KEY;
			} else if ("42000".equals(state)) {
				// MySQL duplicate unique index value on insert
				iciqlCode = CODE_DUPLICATE_KEY;
			} else if ("42Y07".equals(state)) {
				// Derby schema not found
				iciqlCode = CODE_OBJECT_NOT_FOUND;
			} else if ("42X05".equals(state)) {
				// Derby table not found
				iciqlCode = CODE_OBJECT_NOT_FOUND;
			} else if ("42Y55".equals(state)) {
				// Derby table not found
				iciqlCode = CODE_OBJECT_NOT_FOUND;
			} else if ("42S02".equals(state)) {
				// H2 table not found
				iciqlCode = CODE_OBJECT_NOT_FOUND;
			} else if ("42501".equals(state)) {
				// HSQL table not found
				iciqlCode = CODE_OBJECT_NOT_FOUND;
			} else if ("42P01".equals(state)) {
				// PostgreSQL table not found
				iciqlCode = CODE_OBJECT_NOT_FOUND;
			} else if ("X0X05".equals(state)) {
				// Derby view/table not found exists
				iciqlCode = CODE_OBJECT_NOT_FOUND;
			} else if ("X0Y32".equals(state)) {
				// Derby table already exists
				iciqlCode = CODE_OBJECT_ALREADY_EXISTS;
			} else if ("42P07".equals(state)) {
				// PostgreSQL table or index already exists
				iciqlCode = CODE_OBJECT_ALREADY_EXISTS;
			} else if ("42S01".equals(state)) {
				// MySQL view already exists
				iciqlCode = CODE_OBJECT_ALREADY_EXISTS;
			} else if ("42S11".equals(state)) {
				// H2 index already exists
				iciqlCode = CODE_OBJECT_ALREADY_EXISTS;
			} else if ("42504".equals(state)) {
				// HSQL index already exists
				iciqlCode = CODE_OBJECT_ALREADY_EXISTS;
			} else if ("2BP01".equals(state)) {
				// PostgreSQL constraint violation
				iciqlCode = CODE_CONSTRAINT_VIOLATION;
			} else if ("42533".equals(state)) {
				// HSQL constraint violation
				iciqlCode = CODE_CONSTRAINT_VIOLATION;
			} else if ("X0Y25".equals(state)) {
				// Derby constraint violation
				iciqlCode = CODE_CONSTRAINT_VIOLATION;
			} else {
				// uncharacterized SQL code, we can always rely on iciqlCode != 0 in IciqlException
				iciqlCode = s.getErrorCode() == 0 ? CODE_UNCHARACTERIZED : s.getErrorCode();
			}
		}
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append(getClass().getName());
		String message = getLocalizedMessage();
		if (message != null) {
			sb.append(": ").append(message);
		}
		if (sql != null) {
			sb.append('\n').append(sql);
		}
		return sb.toString();
	}
}