KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > dba > postgres > PostgresAdapter


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.dba.postgres;
21
22 import java.sql.Types JavaDoc;
23 import java.util.Iterator JavaDoc;
24
25 import org.apache.cayenne.CayenneRuntimeException;
26 import org.apache.cayenne.access.DataNode;
27 import org.apache.cayenne.access.trans.QualifierTranslator;
28 import org.apache.cayenne.access.trans.QueryAssembler;
29 import org.apache.cayenne.access.types.CharType;
30 import org.apache.cayenne.access.types.ExtendedTypeMap;
31 import org.apache.cayenne.dba.JdbcAdapter;
32 import org.apache.cayenne.dba.PkGenerator;
33 import org.apache.cayenne.dba.TypesMapping;
34 import org.apache.cayenne.map.DbAttribute;
35 import org.apache.cayenne.map.DbEntity;
36 import org.apache.cayenne.map.DerivedDbEntity;
37 import org.apache.cayenne.query.Query;
38 import org.apache.cayenne.query.SQLAction;
39
40 /**
41  * DbAdapter implementation for <a HREF="http://www.postgresql.org">PostgreSQL RDBMS </a>.
42  * Sample <a target="_top"
43  * HREF="../../../../../../../developerguide/unit-tests.html">connection settings </a> to
44  * use with PostgreSQL are shown below:
45  *
46  * <pre>
47  *
48  * test-postgresql.cayenne.adapter = org.apache.cayenne.dba.postgres.PostgresAdapter
49  * test-postgresql.jdbc.username = test
50  * test-postgresql.jdbc.password = secret
51  * test-postgresql.jdbc.url = jdbc:postgresql://serverhostname/cayenne
52  * test-postgresql.jdbc.driver = org.postgresql.Driver
53  *
54  * </pre>
55  *
56  * @author Dirk Olmes
57  * @author Holger Hoffstaette
58  * @author Andrus Adamchik
59  */

60 public class PostgresAdapter extends JdbcAdapter {
61
62     public PostgresAdapter() {
63         setSupportsBatchUpdates(true);
64     }
65
66     /**
67      * Uses PostgresActionBuilder to create the right action.
68      *
69      * @since 1.2
70      */

71     public SQLAction getAction(Query query, DataNode node) {
72         return query.createSQLAction(new PostgresActionBuilder(this, node
73                 .getEntityResolver()));
74     }
75
76     /**
77      * Installs appropriate ExtendedTypes as converters for passing values between JDBC
78      * and Java layers.
79      */

80     protected void configureExtendedTypes(ExtendedTypeMap map) {
81
82         super.configureExtendedTypes(map);
83
84         map.registerType(new CharType(true, false));
85         map.registerType(new PostgresByteArrayType(true, true));
86     }
87
88     public DbAttribute buildAttribute(
89             String JavaDoc name,
90             String JavaDoc typeName,
91             int type,
92             int size,
93             int scale,
94             boolean allowNulls) {
95
96         // "bytea" maps to pretty much any binary type, so
97
// it is up to us to select the most sensible default.
98
// And the winner is LONGVARBINARY
99
if ("bytea".equalsIgnoreCase(typeName)) {
100             type = Types.LONGVARBINARY;
101         }
102         // oid is returned as INTEGER, need to make it BLOB
103
else if ("oid".equals(typeName)) {
104             type = Types.BLOB;
105         }
106         // somehow the driver reverse-engineers "text" as VARCHAR, must be CLOB
107
else if ("text".equalsIgnoreCase(typeName)) {
108             type = Types.CLOB;
109         }
110
111         return super.buildAttribute(name, typeName, type, size, scale, allowNulls);
112     }
113
114     /**
115      * Customizes table creating procedure for PostgreSQL. One difference with generic
116      * implementation is that "bytea" type has no explicit length unlike similar binary
117      * types in other databases.
118      *
119      * @since 1.0.2
120      */

121     public String JavaDoc createTable(DbEntity ent) {
122
123         // later we may support view creation
124
// for derived DbEntities
125
if (ent instanceof DerivedDbEntity) {
126             throw new CayenneRuntimeException("Can't create table for derived DbEntity '"
127                     + ent.getName()
128                     + "'.");
129         }
130
131         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
132         buf.append("CREATE TABLE ").append(ent.getFullyQualifiedName()).append(" (");
133
134         // columns
135
Iterator JavaDoc it = ent.getAttributes().iterator();
136         boolean first = true;
137         while (it.hasNext()) {
138             if (first) {
139                 first = false;
140             }
141             else {
142                 buf.append(", ");
143             }
144
145             DbAttribute at = (DbAttribute) it.next();
146
147             // attribute may not be fully valid, do a simple check
148
if (at.getType() == TypesMapping.NOT_DEFINED) {
149                 throw new CayenneRuntimeException("Undefined type for attribute '"
150                         + ent.getFullyQualifiedName()
151                         + "."
152                         + at.getName()
153                         + "'.");
154             }
155
156             String JavaDoc[] types = externalTypesForJdbcType(at.getType());
157             if (types == null || types.length == 0) {
158                 throw new CayenneRuntimeException("Undefined type for attribute '"
159                         + ent.getFullyQualifiedName()
160                         + "."
161                         + at.getName()
162                         + "': "
163                         + at.getType());
164             }
165
166             String JavaDoc type = types[0];
167             buf.append(at.getName()).append(' ').append(type);
168
169             // append size and precision (if applicable)
170
if (typeSupportsLength(at.getType())) {
171                 int len = at.getMaxLength();
172                 int scale = TypesMapping.isDecimal(at.getType()) ? at.getScale() : -1;
173
174                 // sanity check
175
if (scale > len) {
176                     scale = -1;
177                 }
178
179                 if (len > 0) {
180                     buf.append('(').append(len);
181
182                     if (scale >= 0) {
183                         buf.append(", ").append(scale);
184                     }
185
186                     buf.append(')');
187                 }
188             }
189
190             if (at.isMandatory()) {
191                 buf.append(" NOT NULL");
192             }
193             else {
194                 buf.append(" NULL");
195             }
196         }
197
198         // primary key clause
199
Iterator JavaDoc pkit = ent.getPrimaryKey().iterator();
200         if (pkit.hasNext()) {
201             if (first)
202                 first = false;
203             else
204                 buf.append(", ");
205
206             buf.append("PRIMARY KEY (");
207             boolean firstPk = true;
208             while (pkit.hasNext()) {
209                 if (firstPk)
210                     firstPk = false;
211                 else
212                     buf.append(", ");
213
214                 DbAttribute at = (DbAttribute) pkit.next();
215                 buf.append(at.getName());
216             }
217             buf.append(')');
218         }
219         buf.append(')');
220         return buf.toString();
221     }
222
223     private boolean typeSupportsLength(int type) {
224         // "bytea" type does not support length
225
String JavaDoc[] externalTypes = externalTypesForJdbcType(type);
226         if (externalTypes != null && externalTypes.length > 0) {
227             for (int i = 0; i < externalTypes.length; i++) {
228                 if ("bytea".equalsIgnoreCase(externalTypes[i])) {
229                     return false;
230                 }
231             }
232         }
233
234         return TypesMapping.supportsLength(type);
235     }
236
237     /**
238      * Adds the CASCADE option to the DROP TABLE clause.
239      *
240      * @see JdbcAdapter#dropTable(DbEntity)
241      */

242     public String JavaDoc dropTable(DbEntity ent) {
243         return super.dropTable(ent) + " CASCADE";
244     }
245
246     /**
247      * Returns a trimming translator.
248      */

249     public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) {
250         return new PostgresQualifierTranslator(queryAssembler);
251     }
252
253     /**
254      * @see JdbcAdapter#createPkGenerator()
255      */

256     protected PkGenerator createPkGenerator() {
257         return new PostgresPkGenerator();
258     }
259 }
260
Popular Tags