001 //$HeadURL: svn+ssh://aschmitz@wald.intevation.org/deegree/base/trunk/src/org/deegree/tools/datastore/PostGISDDLGenerator.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2008 by: 006 EXSE, Department of Geography, University of Bonn 007 http://www.giub.uni-bonn.de/deegree/ 008 lat/lon GmbH 009 http://www.lat-lon.de 010 011 This library is free software; you can redistribute it and/or 012 modify it under the terms of the GNU Lesser General Public 013 License as published by the Free Software Foundation; either 014 version 2.1 of the License, or (at your option) any later version. 015 016 This library is distributed in the hope that it will be useful, 017 but WITHOUT ANY WARRANTY; without even the implied warranty of 018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 Lesser General Public License for more details. 020 021 You should have received a copy of the GNU Lesser General Public 022 License along with this library; if not, write to the Free Software 023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 024 025 Contact: 026 027 Andreas Poth 028 lat/lon GmbH 029 Aennchenstraße 19 030 53177 Bonn 031 Germany 032 E-Mail: poth@lat-lon.de 033 034 Prof. Dr. Klaus Greve 035 Department of Geography 036 University of Bonn 037 Meckenheimer Allee 166 038 53115 Bonn 039 Germany 040 E-Mail: greve@giub.uni-bonn.de 041 042 ---------------------------------------------------------------------------*/ 043 package org.deegree.tools.datastore; 044 045 import java.io.IOException; 046 import java.net.MalformedURLException; 047 import java.net.URL; 048 import java.util.ArrayList; 049 import java.util.Collection; 050 import java.util.HashMap; 051 import java.util.Iterator; 052 import java.util.Map; 053 054 import org.deegree.datatypes.Types; 055 import org.deegree.datatypes.UnknownTypeException; 056 import org.deegree.framework.xml.XMLParsingException; 057 import org.deegree.framework.xml.schema.XMLSchemaException; 058 import org.deegree.model.crs.UnknownCRSException; 059 import org.xml.sax.SAXException; 060 061 /** 062 * Generator for Oracle DDL (CREATE / DROP) operations to create Oracle database schemas from annotated GML schema 063 * files. 064 * 065 * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider</a> 066 * @author last edited by: $Author: aschmitz $ 067 * 068 * @version $Revision: 8252 $, $Date: 2007-10-05 11:54:33 +0200 (Fr, 05 Okt 2007) $ 069 */ 070 public class OracleDDLGenerator extends DDLGenerator { 071 072 /** 073 * Generates a new instance of <code>OracleDDLGenerator</code>, ready to generate DDL for the given schema. 074 * 075 * @param schemaURL 076 * @throws MalformedURLException 077 * @throws IOException 078 * @throws SAXException 079 * @throws XMLParsingException 080 * @throws XMLSchemaException 081 * @throws UnknownCRSException 082 */ 083 public OracleDDLGenerator( URL schemaURL ) throws MalformedURLException, IOException, SAXException, 084 XMLParsingException, XMLSchemaException, UnknownCRSException { 085 super( schemaURL ); 086 } 087 088 @Override 089 protected StringBuffer generateDropTableStmt( TableDefinition table ) { 090 StringBuffer sb = new StringBuffer(); 091 sb.append( "DROP TABLE " ); 092 sb.append( table.getName() ); 093 sb.append( " CASCADE CONSTRAINTS;\n" ); 094 095 ColumnDefinition[] columns = table.getColumns(); 096 for ( int i = 0; i < columns.length; i++ ) { 097 if ( columns[i].isGeometry() ) { 098 sb.append( "DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME='" ); 099 sb.append( table.getName() ); 100 sb.append( "';\n" ); 101 break; 102 } 103 } 104 return sb; 105 } 106 107 @Override 108 protected StringBuffer generateCreateTableStmt( TableDefinition table ) { 109 110 Collection<ColumnDefinition> geometryColumns = new ArrayList<ColumnDefinition>(); 111 StringBuffer sb = new StringBuffer( "CREATE TABLE " ); 112 sb.append( table.getName() ); 113 sb.append( " (" ); 114 ColumnDefinition[] columns = table.getColumns(); 115 boolean needComma = false; 116 for ( int i = 0; i < columns.length; i++ ) { 117 if ( !columns[i].isGeometry() ) { 118 if ( needComma ) { 119 sb.append( ',' ); 120 } else { 121 needComma = true; 122 } 123 sb.append( "\n " ); 124 sb.append( columns[i].getName() ); 125 sb.append( ' ' ); 126 String typeName; 127 try { 128 typeName = Types.getTypeNameForSQLTypeCode( columns[i].getType() ); 129 if ( typeName.equals( "DOUBLE" ) ) { 130 typeName = "DOUBLE PRECISION"; 131 } else if ( typeName.equals( "VARCHAR" ) ) { 132 // always prefer VARCHAR2 to VARCHAR: 133 // http://www.orafaq.com/faq/what_is_the_difference_between_varchar_varchar2_and_char_data_types 134 typeName = "VARCHAR2(2000)"; 135 } else if ( typeName.equals( "BOOLEAN" ) ) { 136 typeName = "CHAR(1)"; 137 } 138 } catch ( UnknownTypeException e ) { 139 typeName = "" + columns[i].getType(); 140 } 141 sb.append( typeName ); 142 if ( !columns[i].isNullable() ) { 143 sb.append( " NOT NULL" ); 144 } 145 } else { 146 if ( needComma ) { 147 sb.append( ',' ); 148 } else { 149 needComma = true; 150 } 151 sb.append( "\n " ); 152 sb.append( columns[i].getName() ); 153 sb.append( " MDSYS.SDO_GEOMETRY" ); 154 if ( !columns[i].isNullable() ) { 155 sb.append( " NOT NULL" ); 156 } 157 158 geometryColumns.add( columns[i] ); 159 } 160 } 161 ColumnDefinition[] pkColumns = table.getPKColumns(); 162 if ( pkColumns.length > 0 ) { 163 sb.append( ",\n PRIMARY KEY (" ); 164 for ( int i = 0; i < pkColumns.length; i++ ) { 165 sb.append( pkColumns[i].getName() ); 166 if ( i != pkColumns.length - 1 ) { 167 sb.append( ',' ); 168 } 169 } 170 sb.append( ')' ); 171 } 172 sb.append( "\n);\n" ); 173 174 // add geometry columns 175 for ( ColumnDefinition column : geometryColumns ) { 176 sb.append( "INSERT INTO USER_SDO_GEOM_METADATA VALUES ('" ); 177 sb.append( table.getName() ); 178 sb.append( "', '" ); 179 sb.append( column.getName() ); 180 sb.append( "', SDO_DIM_ARRAY ( SDO_DIM_ELEMENT ( 'LONGITUDE', -180, 180, 0.00005), SDO_DIM_ELEMENT ('LATITUDE',-90,90,0.00005))," ); 181 sb.append( column.getSRS() ); 182 sb.append( ");\n" ); 183 } 184 return sb; 185 } 186 187 @Override 188 protected StringBuffer generateCreateIndexStmts( TableDefinition table ) { 189 StringBuffer sb = new StringBuffer(); 190 191 // build create statements for geometry indexes 192 Collection<ColumnDefinition> geometryColumns = new ArrayList<ColumnDefinition>(); 193 for ( ColumnDefinition column : table.getColumns() ) { 194 if ( column.isGeometry() ) { 195 geometryColumns.add( column ); 196 } 197 } 198 199 Iterator<ColumnDefinition> iter = geometryColumns.iterator(); 200 int spatialIdxCnt = 1; 201 while ( iter.hasNext() ) { 202 ColumnDefinition column = iter.next(); 203 sb.append( "CREATE INDEX " ); 204 String idxSuffix = ( spatialIdxCnt++ ) + "_SPIDX"; 205 String idxName = truncate( table.getName().toUpperCase(), idxSuffix ); 206 sb.append( idxName ); 207 sb.append( " ON " ); 208 sb.append( table.getName() ); 209 sb.append( "(" ); 210 sb.append( column.getName() ); 211 sb.append( ") INDEXTYPE IS MDSYS.SPATIAL_INDEX;" ); 212 sb.append( '\n' ); 213 } 214 215 // build table type specific create index statements 216 switch ( table.getType() ) { 217 case JOIN_TABLE: { 218 // create an index on every column 219 ColumnDefinition[] columns = table.getColumns(); 220 for ( int i = 0; i < columns.length; i++ ) { 221 sb.append( "CREATE INDEX " ); 222 String idxSuffix = '_' + columns[i].getName() + "_IDX"; 223 String idxName = truncate( table.getName().toUpperCase(), idxSuffix ); 224 sb.append( idxName ); 225 sb.append( " ON " ); 226 sb.append( table.getName() ); 227 sb.append( '(' ); 228 sb.append( columns[i].getName() ); 229 sb.append( ");" ); 230 sb.append( '\n' ); 231 } 232 break; 233 } 234 default: { 235 break; 236 } 237 } 238 return sb; 239 } 240 241 @Override 242 protected StringBuffer generateDropIndexStmts( TableDefinition table ) { 243 StringBuffer sb = new StringBuffer(); 244 245 // build drop statements for geometry indexes 246 Collection<ColumnDefinition> geometryColumns = new ArrayList<ColumnDefinition>(); 247 for ( ColumnDefinition column : table.getColumns() ) { 248 if ( column.isGeometry() ) { 249 geometryColumns.add( column ); 250 } 251 } 252 253 Iterator<ColumnDefinition> iter = geometryColumns.iterator(); 254 int spatialIdxCnt = 1; 255 while ( iter.hasNext() ) { 256 iter.next(); 257 sb.append( "DROP INDEX " ); 258 String idxSuffix = ( spatialIdxCnt++ ) + "_SPIDX"; 259 String idxName = truncate( table.getName().toUpperCase(), idxSuffix ); 260 sb.append( idxName ); 261 sb.append( ";\n" ); 262 } 263 264 // build table type specific drop index statements 265 switch ( table.getType() ) { 266 case JOIN_TABLE: { 267 // create an index on every column 268 ColumnDefinition[] columns = table.getColumns(); 269 for ( int i = 0; i < columns.length; i++ ) { 270 sb.append( "DROP INDEX " ); 271 String idxSuffix = '_' + columns[i].getName() + "_IDX"; 272 String idxName = truncate( table.getName().toUpperCase(), idxSuffix ); 273 sb.append( idxName ); 274 sb.append( ";\n" ); 275 } 276 break; 277 } 278 default: { 279 break; 280 } 281 } 282 return sb; 283 } 284 285 Map<String, String> idToTruncatedId = new HashMap<String, String>(); 286 287 int currentId; 288 289 /** 290 * Ensures that the given identifier does not exceed Oracle's limit (30 characters). 291 * 292 * @param identifier 293 * @param suffix 294 * @return the identifier (may be truncated) 295 */ 296 private String truncate( String identifier, String suffix ) { 297 String truncatedIdentifier = idToTruncatedId.get( identifier + suffix ); 298 if ( truncatedIdentifier == null ) { 299 truncatedIdentifier = identifier + suffix; 300 if ( truncatedIdentifier.length() > 30 ) { 301 System.out.print( "Generated identifier name '" + truncatedIdentifier 302 + "' exceeds 30 characters (Oracle limit)." ); 303 truncatedIdentifier = identifier.substring( 0, 30 - suffix.length() - ( "" + currentId ).length() ) 304 + ( currentId++ ) + suffix; 305 System.out.println( " Truncated to: '" + truncatedIdentifier + "'." ); 306 } 307 idToTruncatedId.put( identifier + suffix, truncatedIdentifier ); 308 } 309 return truncatedIdentifier; 310 } 311 }