(empty log message)
@@ -0,0 +1,65 @@ | ||
1 | +import java.sql.Connection; | |
2 | +import java.sql.DriverManager; | |
3 | +import java.sql.SQLException; | |
4 | + | |
5 | +import org.junit.Before; | |
6 | +import org.junit.Test; | |
7 | + | |
8 | +import estoc.dbm.AccessManager; | |
9 | +import estoc.dbm.DataAccess; | |
10 | +import estoc.dbm.DbType; | |
11 | +import estoc.dbm.TableAccess; | |
12 | + | |
13 | +public class TestAnnotateOracle extends TestAnnotate { | |
14 | + private Connection conn; | |
15 | + private AccessManager am; | |
16 | + | |
17 | + @Override @Before | |
18 | + public void setup() throws Exception { | |
19 | + dropBeforeCreate = true; | |
20 | + Class.forName("oracle.jdbc.driver.OracleDriver"); | |
21 | + conn =DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe","test","test"); | |
22 | + am = new AccessManager(DbType.Oracle); | |
23 | + } | |
24 | + | |
25 | + @Override | |
26 | + protected DataAccess getDataAccess() { | |
27 | + return am.getDataAccess(conn); | |
28 | + } | |
29 | + | |
30 | + @Override | |
31 | + protected TableAccess getTableAccess() { | |
32 | + return am.getTableAccess(conn); | |
33 | + } | |
34 | + //------------------------------------------------------ | |
35 | + @Override @Test | |
36 | + public void testAutoInc() throws SQLException { | |
37 | + super.testAutoInc(); | |
38 | + } | |
39 | + | |
40 | + @Override @Test | |
41 | + public void testIndex() throws SQLException { | |
42 | + super.testIndex(); | |
43 | + } | |
44 | + | |
45 | + @Override @Test | |
46 | + public void testNotNull() throws SQLException { | |
47 | + super.testNotNull(); | |
48 | + } | |
49 | + | |
50 | + @Override @Test | |
51 | + public void testPk() throws SQLException { | |
52 | + super.testPk(); | |
53 | + } | |
54 | + | |
55 | + @Override @Test | |
56 | + public void testTimeStamp() throws SQLException { | |
57 | + super.testTimeStamp(); | |
58 | + } | |
59 | + | |
60 | + @Override @Test | |
61 | + public void testUnique() throws SQLException { | |
62 | + super.testUnique(); | |
63 | + } | |
64 | + | |
65 | +} |
@@ -11,7 +11,10 @@ | ||
11 | 11 | TestAnnotatePgsql.class,// |
12 | 12 | TestDbTypePgsql.class, // |
13 | 13 | TestAnnotateMysql.class,// |
14 | - TestDbTypeMysql.class // | |
14 | + TestDbTypeMysql.class, // | |
15 | + TestAnnotateOracle.class,// | |
16 | + TestDbTypeOracle.class, // | |
17 | + | |
15 | 18 | }) |
16 | 19 | public class AllTests { |
17 | 20 | } |
@@ -0,0 +1,82 @@ | ||
1 | +import java.sql.Connection; | |
2 | +import java.sql.DriverManager; | |
3 | +import java.sql.SQLException; | |
4 | + | |
5 | +import org.junit.Before; | |
6 | +import org.junit.BeforeClass; | |
7 | +import org.junit.Test; | |
8 | + | |
9 | +import estoc.dbm.AccessManager; | |
10 | +import estoc.dbm.DataAccess; | |
11 | +import estoc.dbm.DbType; | |
12 | +import estoc.dbm.TableAccess; | |
13 | + | |
14 | +public class TestDbTypeOracle extends TestDbType { | |
15 | + private Connection conn; | |
16 | + private AccessManager am; | |
17 | + | |
18 | + @BeforeClass | |
19 | + public static void preStart() throws Exception { | |
20 | + } | |
21 | + | |
22 | + @Override | |
23 | + @Before | |
24 | + public void setup() throws Exception { | |
25 | + dropBeforeCreate = true; | |
26 | + Class.forName("oracle.jdbc.driver.OracleDriver"); | |
27 | + conn =DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe","test","test"); | |
28 | + am = new AccessManager(DbType.Oracle); | |
29 | + } | |
30 | + | |
31 | + @Override | |
32 | + protected DataAccess getDataAccess() { | |
33 | + return am.getDataAccess(conn); | |
34 | + } | |
35 | + | |
36 | + @Override | |
37 | + protected TableAccess getTableAccess() { | |
38 | + return am.getTableAccess(conn); | |
39 | + } | |
40 | + | |
41 | + // ------------------------------------------------------ | |
42 | + @Override | |
43 | + @Test | |
44 | + public void testTypeBigDecimal() throws SQLException { | |
45 | + super.testTypeBigDecimal(); | |
46 | + } | |
47 | + | |
48 | + @Override | |
49 | + @Test | |
50 | + public void testTypeBoolean() throws SQLException { | |
51 | + super.testTypeBoolean(); | |
52 | + } | |
53 | + | |
54 | + @Override | |
55 | + @Test | |
56 | + public void testTypeBytes() throws SQLException { | |
57 | + super.testTypeBytes(); | |
58 | + } | |
59 | + | |
60 | + @Override | |
61 | + @Test | |
62 | + public void testTypeDate() throws SQLException { | |
63 | + super.testTypeDate(); | |
64 | + } | |
65 | + | |
66 | + @Override | |
67 | + public void testTypeDouble() throws SQLException { | |
68 | + super.testTypeDouble(); | |
69 | + } | |
70 | + | |
71 | + @Override | |
72 | + @Test | |
73 | + public void testTypeInteger() throws SQLException { | |
74 | + super.testTypeInteger(); | |
75 | + } | |
76 | + | |
77 | + @Override | |
78 | + @Test | |
79 | + public void testTypeString() throws SQLException { | |
80 | + super.testTypeString(); | |
81 | + } | |
82 | +} |
@@ -0,0 +1,183 @@ | ||
1 | +package estoc.dbm; | |
2 | + | |
3 | +import java.sql.Connection; | |
4 | +import java.sql.SQLException; | |
5 | +import java.util.ArrayList; | |
6 | +import java.util.List; | |
7 | + | |
8 | +class TableAccessOracle extends TableAccess { | |
9 | + public TableAccessOracle(Connection connection) { | |
10 | + super(connection); | |
11 | + } | |
12 | + | |
13 | + @Override | |
14 | + public void drop(Class<?> clz) throws SQLException { | |
15 | + String tableName = getTableName(clz); | |
16 | + | |
17 | + StringBuilder sb = new StringBuilder(); | |
18 | + sb.append("DROP TABLE ").append(tableName).toString(); | |
19 | + try { | |
20 | + executeDiretory(sb.toString()); | |
21 | + } catch (SQLException e) { | |
22 | + if ("42000".equals(e.getSQLState())) { | |
23 | + return; // 存在しないTBLの削除 | |
24 | + } | |
25 | + throw e; | |
26 | + } | |
27 | + | |
28 | + List<ColumnInfo> columnInfo = getColumnInfo(clz); | |
29 | + for (ColumnInfo info : columnInfo) { | |
30 | + if (info.isAutoInc()) { | |
31 | + sb = new StringBuilder(); | |
32 | + sb.append("DROP SEQUENCE ").append(getSequenceName(tableName, info.getName())); | |
33 | + try { | |
34 | + executeDiretory(sb.toString()); | |
35 | + } catch (SQLException e) { | |
36 | + if ("42000".equals(e.getSQLState())) { | |
37 | + return; // 存在しないTBLの削除 | |
38 | + } | |
39 | + throw e; | |
40 | + } | |
41 | + } | |
42 | + } | |
43 | + | |
44 | + } | |
45 | + | |
46 | + @Override | |
47 | + public void create(Class<?> clz) throws SQLException { | |
48 | + String tableName = getTableName(clz); | |
49 | + List<ColumnInfo> columns = getColumnInfo(clz); | |
50 | + validate(columns); | |
51 | + String sql = createTableSql(tableName, columns); | |
52 | + executeDiretory(sql); | |
53 | + for (ColumnInfo info : columns) { | |
54 | + if (info.isIndex()) { | |
55 | + sql = createIndexSql(tableName, info); | |
56 | + executeDiretory(sql); | |
57 | + } | |
58 | + if (info.isAutoInc()) { | |
59 | + sql = createSequenceSql(tableName, info); | |
60 | + executeDiretory(sql); | |
61 | + } | |
62 | + } | |
63 | + } | |
64 | + | |
65 | + private void validate(List<ColumnInfo> columns) { | |
66 | + boolean autoIncExist = false; | |
67 | + for (ColumnInfo info : columns) { | |
68 | + // PK と TimeStamp は同時に指定できない | |
69 | + if (info.isPk() && info.isTimeStamp()) { | |
70 | + throw new UnsupportedOperationException("@Pk and @TimeStam are can't define together"); | |
71 | + } | |
72 | + if (info.isAutoInc()) { | |
73 | + // AutoIncのみのテーブルは許可しない | |
74 | + if (columns.size() == 1) { | |
75 | + throw new UnsupportedOperationException("@AutoInc must be another columns"); | |
76 | + } | |
77 | + // AutoIncは複数のカラムには付与できない | |
78 | + if (autoIncExist) { | |
79 | + throw new UnsupportedOperationException("@AutoInc can't define multi columns"); | |
80 | + } | |
81 | + autoIncExist = true; | |
82 | + } | |
83 | + // 型のチェック | |
84 | + getDbType(info.getType(), info.getTypeOpt1(), info.getTypeOpt2()); | |
85 | + } | |
86 | + } | |
87 | + | |
88 | + private String createTableSql(String tableName, List<ColumnInfo> columns) { | |
89 | + StringBuilder sb = new StringBuilder(); | |
90 | + sb.append(" CREATE TABLE ").append(tableName).append(" ( "); | |
91 | + boolean next = false; | |
92 | + List<String> pks = new ArrayList<String>(); | |
93 | + for (ColumnInfo info : columns) { | |
94 | + if (next) { | |
95 | + sb.append(","); | |
96 | + } else { | |
97 | + next = true; | |
98 | + } | |
99 | + sb.append(info.getName()).append(" "); | |
100 | + sb.append(getDbType(info.getType(), info.getTypeOpt1(), info.getTypeOpt2())); | |
101 | + if (info.isNotNull() || info.isPk() || info.isAutoInc()) { | |
102 | + sb.append(" NOT NULL "); // Oracleではauto_incに相当するタイプが無い | |
103 | + } | |
104 | + if (info.isPk()) { | |
105 | + pks.add(info.getName()); | |
106 | + } | |
107 | + if (info.isUnique()) { | |
108 | + sb.append(" UNIQUE "); | |
109 | + } | |
110 | + } | |
111 | + if (pks.size() > 0) { | |
112 | + sb.append(", PRIMARY KEY ("); | |
113 | + sb.append(DbmUtil.toCommaString(pks.toArray(), ",", null)); | |
114 | + sb.append(" )"); | |
115 | + } | |
116 | + sb.append(" ) "); | |
117 | + return sb.toString(); | |
118 | + } | |
119 | + | |
120 | + private String createIndexSql(String tableName, ColumnInfo column) { | |
121 | + StringBuilder sb = new StringBuilder(); | |
122 | + sb.append(" CREATE INDEX ").append("idx_").append(column.getName()); | |
123 | + sb.append(" ON ").append(tableName).append(" (").append(column.getName()).append(")"); | |
124 | + return sb.toString(); | |
125 | + } | |
126 | + | |
127 | + private String createSequenceSql(String tableName, ColumnInfo column) { | |
128 | + StringBuilder sb = new StringBuilder(); | |
129 | + sb.append(" CREATE SEQUENCE ").append(getSequenceName(tableName, column.getName())); | |
130 | + return sb.toString(); | |
131 | + } | |
132 | + | |
133 | + private String getSequenceName(String tableName, String columnName) { | |
134 | + StringBuilder sb = new StringBuilder(); | |
135 | + sb.append("seq_").append(tableName).append("_").append(columnName); | |
136 | + return sb.toString(); | |
137 | + } | |
138 | + | |
139 | + @Override | |
140 | + protected String getBinaryType(int opt) { | |
141 | + return "BLOB"; | |
142 | + } | |
143 | + | |
144 | + @Override | |
145 | + protected String getDateType(int opt) { | |
146 | + return "TIMESTAMP"; | |
147 | + } | |
148 | + | |
149 | + @Override | |
150 | + protected String getIntType(int opt) { | |
151 | + return "INTEGER"; | |
152 | + } | |
153 | + | |
154 | + @Override | |
155 | + protected String getStringType(int opt) { | |
156 | + if (opt == -1) { | |
157 | + return "VARCHAR(125)"; // defaultでMAX 125文字とする | |
158 | + } else { | |
159 | + return "VARCHAR(" + opt + ")"; | |
160 | + } | |
161 | + } | |
162 | + | |
163 | + @Override | |
164 | + protected String getBooleanType(int opt) { | |
165 | + throw new UnsupportedOperationException(); | |
166 | + } | |
167 | + | |
168 | + @Override | |
169 | + protected String getDoubleType(int opt) { | |
170 | + return "DOUBLE"; | |
171 | + } | |
172 | + | |
173 | + @Override | |
174 | + protected String getDecimalType(int opt1, int opt2) { | |
175 | + if (opt1 == -1) { | |
176 | + opt1 = 10; | |
177 | + } | |
178 | + if (opt2 == -1) { | |
179 | + opt2 = 0; | |
180 | + } | |
181 | + return "DECIMAL(" + opt1 + "," + opt2 + ")"; | |
182 | + } | |
183 | +} |
@@ -0,0 +1,389 @@ | ||
1 | +package estoc.dbm; | |
2 | + | |
3 | +import java.io.ByteArrayInputStream; | |
4 | +import java.io.InputStream; | |
5 | +import java.lang.reflect.Field; | |
6 | +import java.math.BigDecimal; | |
7 | +import java.sql.Connection; | |
8 | +import java.sql.PreparedStatement; | |
9 | +import java.sql.ResultSet; | |
10 | +import java.sql.SQLException; | |
11 | +import java.sql.Types; | |
12 | +import java.util.ArrayList; | |
13 | +import java.util.Date; | |
14 | +import java.util.HashMap; | |
15 | +import java.util.LinkedHashSet; | |
16 | +import java.util.List; | |
17 | +import java.util.Map; | |
18 | +import java.util.Set; | |
19 | +import java.util.logging.Logger; | |
20 | + | |
21 | +import estoc.dbm.annotate.Table; | |
22 | + | |
23 | +class DataAccessOracleImpl implements DataAccess { | |
24 | + private final static Logger LOG = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); | |
25 | + private final Connection connection; | |
26 | + private final SqlCreator creator; | |
27 | + | |
28 | + public DataAccessOracleImpl(Connection connection, SqlCreator creator) { | |
29 | + this.connection = connection; | |
30 | + this.creator = creator; | |
31 | + } | |
32 | + | |
33 | + Map<Class<?>, List<ColumnInfo>> fieldMap = new HashMap<Class<?>, List<ColumnInfo>>(); | |
34 | + Map<Class<?>, PreparedStatement> selectStmts = new HashMap<Class<?>, PreparedStatement>(); | |
35 | + Map<Class<?>, PreparedStatement> insertStmts = new HashMap<Class<?>, PreparedStatement>(); | |
36 | + Map<Class<?>, PreparedStatement> autoKeyStmts = new HashMap<Class<?>, PreparedStatement>(); | |
37 | + Map<Class<?>, PreparedStatement> updateStmts = new HashMap<Class<?>, PreparedStatement>(); | |
38 | + Map<Class<?>, PreparedStatement> deleteStmts = new HashMap<Class<?>, PreparedStatement>(); | |
39 | + | |
40 | + private List<ColumnInfo> getDeclaredFields(Class<?> clz) { | |
41 | + List<ColumnInfo> fields = fieldMap.get(clz); | |
42 | + if (fields == null) { | |
43 | + fields = new ArrayList<ColumnInfo>(); | |
44 | + Field[] declaredFields = clz.getDeclaredFields(); | |
45 | + for (Field field : declaredFields) { | |
46 | + fields.add(new ColumnInfo(field)); | |
47 | + } | |
48 | + fieldMap.put(clz, fields); | |
49 | + } | |
50 | + return fields; | |
51 | + } | |
52 | + | |
53 | + /* | |
54 | + * (non-Javadoc) | |
55 | + * | |
56 | + * @see dbm.DataAccess#select(java.lang.Class, java.lang.Object) | |
57 | + */ | |
58 | + public <T> T select(Class<T> clz, Object... params) throws SQLException { | |
59 | + PreparedStatement stmt = selectStmts.get(clz); | |
60 | + if (stmt == null || stmt.getConnection() != connection) { | |
61 | + stmt = createSelectStmt(clz); | |
62 | + } | |
63 | + setParams(stmt, params); | |
64 | + ResultSet result = stmt.executeQuery(); | |
65 | + if (result != null && result.next()) { | |
66 | + return DbmUtil.fillData(clz, result); | |
67 | + } | |
68 | + return null; | |
69 | + } | |
70 | + | |
71 | + private <T> PreparedStatement createSelectStmt(Class<T> clz) throws SQLException { | |
72 | + PreparedStatement stmt; | |
73 | + Set<String> cols = new LinkedHashSet<String>(); | |
74 | + Set<String> pks = new LinkedHashSet<String>(); | |
75 | + for (Field field : clz.getDeclaredFields()) { | |
76 | + ColumnInfo info = new ColumnInfo(field); | |
77 | + if (info.isColumn()) { | |
78 | + cols.add(field.getName()); | |
79 | + if (info.isPk()) { | |
80 | + pks.add(field.getName()); | |
81 | + } | |
82 | + } | |
83 | + } | |
84 | + if (pks.size() == 0) { | |
85 | + throw new UnsupportedOperationException("When if you use SELECT, table have to be defined PK"); | |
86 | + } | |
87 | + String tableName = getTableName(clz); | |
88 | + String selectSql = creator.getSelectSql(tableName, pks, cols); | |
89 | + stmt = connection.prepareStatement(selectSql); | |
90 | + selectStmts.put(clz, stmt); | |
91 | + return stmt; | |
92 | + } | |
93 | + | |
94 | + /* | |
95 | + * (non-Javadoc) | |
96 | + * | |
97 | + * @see dbm.DataAccess#delete(java.lang.Object) | |
98 | + */ | |
99 | + public boolean delete(Object obj) throws SQLException { | |
100 | + Class<?> clz = obj.getClass(); | |
101 | + PreparedStatement stmt = deleteStmts.get(clz); | |
102 | + if (stmt == null || stmt.getConnection() != connection) { | |
103 | + stmt = createDeleteStmt(clz); | |
104 | + } | |
105 | + List<Object> params = new ArrayList<Object>(); | |
106 | + for (ColumnInfo info : getDeclaredFields(clz)) { | |
107 | + if (info.isPk()) { | |
108 | + params.add(DbmUtil.getVlaueFromField(obj, info)); | |
109 | + } | |
110 | + } | |
111 | + setParams(stmt, params.toArray()); | |
112 | + return stmt.executeUpdate() == 1; | |
113 | + } | |
114 | + | |
115 | + private PreparedStatement createDeleteStmt(Class<?> clz) throws SQLException { | |
116 | + PreparedStatement stmt; | |
117 | + Set<String> pks = new LinkedHashSet<String>(); | |
118 | + for (ColumnInfo info : getDeclaredFields(clz)) { | |
119 | + if (info.isPk()) { | |
120 | + pks.add(info.getName()); | |
121 | + } | |
122 | + } | |
123 | + if (pks.size() == 0) { | |
124 | + throw new UnsupportedOperationException("When if you use DELETE, table have to be defined PK"); | |
125 | + } | |
126 | + String tableName = getTableName(clz); | |
127 | + String sql = creator.getDeleteSql(tableName, pks); | |
128 | + LOG.info("sql = " + sql); | |
129 | + stmt = connection.prepareStatement(sql); | |
130 | + deleteStmts.put(clz, stmt); | |
131 | + return stmt; | |
132 | + } | |
133 | + | |
134 | + /* | |
135 | + * (non-Javadoc) | |
136 | + * | |
137 | + * @see dbm.DataAccess#insert(java.lang.Object) | |
138 | + */ | |
139 | + public <T> T insert(T obj) throws SQLException { | |
140 | + Class<?> clz = obj.getClass(); | |
141 | + | |
142 | + PreparedStatement getKeyStmt; | |
143 | + if (autoKeyStmts.containsKey(clz)) { | |
144 | + getKeyStmt = autoKeyStmts.get(clz); | |
145 | + } else { | |
146 | + getKeyStmt = createGetKeyStmt(clz); | |
147 | + } | |
148 | + | |
149 | + int nextVal = -1; | |
150 | + if (getKeyStmt != null) { | |
151 | + ResultSet rs = getKeyStmt.executeQuery(); | |
152 | + if (rs.next()) { | |
153 | + nextVal = rs.getInt(1); | |
154 | + } else { | |
155 | + throw new RuntimeException("Faild to get nextval for auto inc."); | |
156 | + } | |
157 | + | |
158 | + } | |
159 | + | |
160 | + PreparedStatement stmt = insertStmts.get(clz); | |
161 | + // create statement | |
162 | + if (stmt == null || stmt.getConnection() != connection) { | |
163 | + stmt = createInsertStmt(clz); | |
164 | + } | |
165 | + // set value | |
166 | + List<Object> params = new ArrayList<Object>(); | |
167 | + Date now = new Date(); | |
168 | + ColumnInfo autoIncField = null; | |
169 | + List<ColumnInfo> timeFields = new ArrayList<ColumnInfo>(); | |
170 | + for (ColumnInfo info : getDeclaredFields(clz)) { | |
171 | + if (info.isColumn()) { | |
172 | + if (info.isAutoInc()) { | |
173 | + autoIncField = info; | |
174 | + params.add(nextVal); | |
175 | + } else if (info.isTimeStamp()) { | |
176 | + timeFields.add(info); | |
177 | + params.add(now); | |
178 | + } else { | |
179 | + params.add(DbmUtil.getVlaueFromField(obj, info)); | |
180 | + } | |
181 | + } | |
182 | + } | |
183 | + setParams(stmt, params.toArray()); | |
184 | + // Do insert | |
185 | + if (stmt.executeUpdate() == 1) { | |
186 | + // AutoInc, TimeStamp の値埋め込み | |
187 | + for (ColumnInfo info : timeFields) { | |
188 | + DbmUtil.setVlaueToField(obj, info, now); | |
189 | + } | |
190 | + if (autoIncField != null) { | |
191 | + if (autoIncField.getType() == Integer.class) { | |
192 | + DbmUtil.setVlaueToField(obj, autoIncField, new Integer(nextVal)); | |
193 | + } else if (autoIncField.getType() == Long.class) { | |
194 | + DbmUtil.setVlaueToField(obj, autoIncField, new Long(nextVal)); | |
195 | + } else { | |
196 | + throw new UnsupportedOperationException("Unsupport type:" + autoIncField.getType()); | |
197 | + } | |
198 | + } | |
199 | + return obj; | |
200 | + } else { | |
201 | + return null; | |
202 | + } | |
203 | + } | |
204 | + | |
205 | + /** | |
206 | + * serialの次番を取得するStatementを作成します AutoInc列が存在しない場合nullを返します | |
207 | + * | |
208 | + * @param clz | |
209 | + * @return | |
210 | + * @throws SQLException | |
211 | + */ | |
212 | + private PreparedStatement createGetKeyStmt(Class<?> clz) throws SQLException { | |
213 | + PreparedStatement stmt; | |
214 | + String colName = null; | |
215 | + for (ColumnInfo info : getDeclaredFields(clz)) { | |
216 | + if (info.isColumn()) { | |
217 | + if (info.isAutoInc()) { | |
218 | + colName = info.getName(); | |
219 | + break; | |
220 | + } | |
221 | + } | |
222 | + } | |
223 | + if (colName == null) { | |
224 | + autoKeyStmts.put(clz, null); | |
225 | + return null; | |
226 | + } | |
227 | + | |
228 | + StringBuilder sb = new StringBuilder(); | |
229 | + | |
230 | + // select seq_01.nextval as nextval from dual | |
231 | + | |
232 | + | |
233 | + sb.append("SELECT ") | |
234 | + .append("seq_") | |
235 | + .append(getTableName(clz)) | |
236 | + .append("_").append(colName) | |
237 | + .append(".nextval FROM dual"); | |
238 | + stmt = connection.prepareStatement(sb.toString()); | |
239 | + autoKeyStmts.put(clz, stmt); | |
240 | + return stmt; | |
241 | + } | |
242 | + | |
243 | + private PreparedStatement createInsertStmt(Class<?> clz) throws SQLException { | |
244 | + PreparedStatement stmt; | |
245 | + Set<String> columns = new LinkedHashSet<String>(); | |
246 | + for (ColumnInfo info : getDeclaredFields(clz)) { | |
247 | + if (info.isColumn()) { | |
248 | + // oracleではAutoIncもパラメータとして与える | |
249 | + columns.add(info.getName()); | |
250 | + } | |
251 | + } | |
252 | + String tableName = getTableName(clz); | |
253 | + String sql = creator.getInsertSql(tableName, columns); | |
254 | + LOG.info("sql= " + sql); | |
255 | + | |
256 | + stmt = connection.prepareStatement(sql); | |
257 | + insertStmts.put(clz, stmt); | |
258 | + return stmt; | |
259 | + } | |
260 | + | |
261 | + /* | |
262 | + * (non-Javadoc) | |
263 | + * | |
264 | + * @see dbm.DataAccess#update(java.lang.Object, boolean) | |
265 | + */ | |
266 | + public <T> T update(T obj) throws SQLException { | |
267 | + Class<?> clz = obj.getClass(); | |
268 | + PreparedStatement stmt = updateStmts.get(clz); | |
269 | + if (stmt == null || stmt.getConnection() != connection) { | |
270 | + stmt = createUpdateStmt(clz); | |
271 | + } | |
272 | + // set value | |
273 | + List<Object> params = new ArrayList<Object>(); | |
274 | + List<Object> pkParams = new ArrayList<Object>(); | |
275 | + List<ColumnInfo> timeFields = new ArrayList<ColumnInfo>(); | |
276 | + Date now = new Date(); | |
277 | + for (ColumnInfo info : getDeclaredFields(clz)) { | |
278 | + if (info.isPk()) { | |
279 | + pkParams.add(DbmUtil.getVlaueFromField(obj, info)); | |
280 | + } else { | |
281 | + if (info.isColumn()) { | |
282 | + if (info.isTimeStamp()) { | |
283 | + timeFields.add(info); | |
284 | + params.add(now); | |
285 | + } else { | |
286 | + params.add(DbmUtil.getVlaueFromField(obj, info)); | |
287 | + } | |
288 | + } | |
289 | + } | |
290 | + } | |
291 | + List<Object> tmp = new ArrayList<Object>(); | |
292 | + tmp.addAll(params); | |
293 | + tmp.addAll(pkParams); | |
294 | + setParams(stmt, tmp.toArray()); | |
295 | + // do update | |
296 | + if (stmt.executeUpdate() == 1) { | |
297 | + for (ColumnInfo info : timeFields) { | |
298 | + DbmUtil.setVlaueToField(obj, info, now); | |
299 | + } | |
300 | + return obj; | |
301 | + } else { | |
302 | + return null; | |
303 | + } | |
304 | + } | |
305 | + | |
306 | + private PreparedStatement createUpdateStmt(Class<?> clz) throws SQLException { | |
307 | + PreparedStatement stmt; | |
308 | + Set<String> pks = new LinkedHashSet<String>(); | |
309 | + Set<String> columns = new LinkedHashSet<String>(); | |
310 | + for (ColumnInfo info : getDeclaredFields(clz)) { | |
311 | + if (info.isPk()) { | |
312 | + pks.add(info.getName()); | |
313 | + } else { | |
314 | + if (info.isColumn()) { | |
315 | + columns.add(info.getName()); | |
316 | + } | |
317 | + } | |
318 | + } | |
319 | + if (pks.size() == 0) { | |
320 | + throw new UnsupportedOperationException("When if you use UPDATE, table have to be defined PK"); | |
321 | + } | |
322 | + String tableName = getTableName(clz); | |
323 | + String sql = creator.getUpdateSql(tableName, pks, columns); | |
324 | + LOG.info("sql= " + sql); | |
325 | + stmt = connection.prepareStatement(sql); | |
326 | + updateStmts.put(clz, stmt); | |
327 | + return stmt; | |
328 | + } | |
329 | + | |
330 | + private String getTableName(Class<?> clz) { | |
331 | + Table table = clz.getAnnotation(Table.class); | |
332 | + return table.value(); | |
333 | + } | |
334 | + | |
335 | + private int getSqlType(Class<?> type) { | |
336 | + if (type == String.class) { | |
337 | + return Types.VARCHAR; | |
338 | + } else if (type == Date.class) { | |
339 | + return Types.DATE; | |
340 | + } else if (type == Integer.class) { | |
341 | + return Types.INTEGER; | |
342 | + } else if (type == BigDecimal.class) { | |
343 | + return Types.DECIMAL; | |
344 | + } else if (type == Double.class) { | |
345 | + return Types.DOUBLE; | |
346 | + } else if (type == Boolean.class) { | |
347 | + return Types.BOOLEAN; | |
348 | + } else if (type == byte[].class) { | |
349 | + return Types.VARBINARY; | |
350 | + } else { | |
351 | + throw new UnsupportedOperationException("Unsupport type " + type); | |
352 | + } | |
353 | + } | |
354 | + | |
355 | + private void setParams(PreparedStatement stmt, Object[] params) throws SQLException { | |
356 | + int i = 1; | |
357 | + for (Object object : params) { | |
358 | + Class<?> type; | |
359 | + if (object instanceof TypedNull) { | |
360 | + type = ((TypedNull) object).getType(); | |
361 | + int sqlType = getSqlType(type); | |
362 | + stmt.setNull(i, sqlType); | |
363 | + } else { | |
364 | + type = object.getClass(); | |
365 | + if (type == String.class) { | |
366 | + stmt.setString(i, (String) object); | |
367 | + } else if (type == Date.class) { | |
368 | + Date date = (Date) object; | |
369 | + stmt.setTimestamp(i, new java.sql.Timestamp(date.getTime())); | |
370 | + } else if (type == Integer.class) { | |
371 | + stmt.setInt(i, (Integer) object); | |
372 | + } else if (type == BigDecimal.class) { | |
373 | + stmt.setBigDecimal(i, (BigDecimal) object); | |
374 | + } else if (type == Double.class) { | |
375 | + stmt.setDouble(i, (Double) object); | |
376 | + } else if (type == Boolean.class) { | |
377 | + stmt.setBoolean(i, (Boolean) object); | |
378 | + } else if (type == byte[].class) { | |
379 | + byte[] bytes = (byte[]) object; | |
380 | + InputStream is = new ByteArrayInputStream(bytes); | |
381 | + stmt.setBinaryStream(i, is, bytes.length); | |
382 | + } else { | |
383 | + throw new UnsupportedOperationException("Unsupport type " + object); | |
384 | + } | |
385 | + } | |
386 | + i++; | |
387 | + } | |
388 | + } | |
389 | +} |
@@ -3,6 +3,7 @@ | ||
3 | 3 | import java.lang.reflect.Field; |
4 | 4 | import java.math.BigDecimal; |
5 | 5 | import java.sql.Connection; |
6 | +import java.sql.ResultSet; | |
6 | 7 | import java.sql.SQLException; |
7 | 8 | import java.util.ArrayList; |
8 | 9 | import java.util.Date; |
@@ -91,4 +92,9 @@ | ||
91 | 92 | LOG.info("sql= " + sql); |
92 | 93 | connection.createStatement().executeUpdate(sql); |
93 | 94 | } |
95 | + | |
96 | + protected ResultSet executeQuery(String sql) throws SQLException { | |
97 | + LOG.info("sql= " + sql); | |
98 | + return connection.createStatement().executeQuery(sql); | |
99 | + } | |
94 | 100 | } |
@@ -4,5 +4,6 @@ | ||
4 | 4 | H2, |
5 | 5 | Derby, |
6 | 6 | Postgresql, |
7 | - Mysql | |
7 | + Mysql, | |
8 | + Oracle | |
8 | 9 | } |
@@ -23,6 +23,8 @@ | ||
23 | 23 | return new DataAccessImpl(connection, creator); |
24 | 24 | case Postgresql: |
25 | 25 | return new DataAccessPgsqlImpl(connection, creator); |
26 | + case Oracle: | |
27 | + return new DataAccessOracleImpl(connection, creator); | |
26 | 28 | default: |
27 | 29 | throw new UnsupportedOperationException("DbType=" + dbType); |
28 | 30 |
@@ -44,6 +46,9 @@ | ||
44 | 46 | case Mysql: |
45 | 47 | tableAccess = new TableAccessMysql(connection); |
46 | 48 | break; |
49 | + case Oracle: | |
50 | + tableAccess = new TableAccessOracle(connection); | |
51 | + break; | |
47 | 52 | default: |
48 | 53 | throw new UnsupportedOperationException("DbType=" + dbType); |
49 | 54 | } |