View Javadoc
1 package org.apache.torque.engine.database.transform; 2 3 /* ==================================================================== 4 * The Apache Software License, Version 1.1 5 * 6 * Copyright (c) 2001 The Apache Software Foundation. All rights 7 * reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The end-user documentation included with the redistribution, 22 * if any, must include the following acknowledgment: 23 * "This product includes software developed by the 24 * Apache Software Foundation (http://www.apache.org/)." 25 * Alternately, this acknowledgment may appear in the software itself, 26 * if and wherever such third-party acknowledgments normally appear. 27 * 28 * 4. The names "Apache" and "Apache Software Foundation" and 29 * "Apache Turbine" must not be used to endorse or promote products 30 * derived from this software without prior written permission. For 31 * written permission, please contact apache@apache.org. 32 * 33 * 5. Products derived from this software may not be called "Apache", 34 * "Apache Turbine", nor may "Apache" appear in their name, without 35 * prior written permission of the Apache Software Foundation. 36 * 37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * ==================================================================== 50 * 51 * This software consists of voluntary contributions made by many 52 * individuals on behalf of the Apache Software Foundation. For more 53 * information on the Apache Software Foundation, please see 54 * <http://www.apache.org/>. 55 */ 56 57 import java.io.BufferedReader; 58 import java.io.FileReader; 59 import java.io.IOException; 60 import java.util.ArrayList; 61 import java.util.List; 62 import org.apache.torque.engine.database.model.AppData; 63 import org.apache.torque.engine.database.model.Column; 64 import org.apache.torque.engine.database.model.Database; 65 import org.apache.torque.engine.database.model.ForeignKey; 66 import org.apache.torque.engine.database.model.IDMethod; 67 import org.apache.torque.engine.database.model.Table; 68 import org.apache.torque.engine.sql.ParseException; 69 import org.apache.torque.engine.sql.SQLScanner; 70 import org.apache.torque.engine.sql.Token; 71 72 /*** 73 * A Class that converts an sql input file to an AppData 74 * structure. The class makes use of SQL Scanner to get 75 * sql tokens and the parses these to create the AppData 76 * class. SQLToAppData is in effect a simplified sql parser. 77 * 78 * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a> 79 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> 80 * @version $Id: SQLToAppData.java,v 1.2 2003/02/18 08:05:50 mpoeschl Exp $ 81 */ 82 public class SQLToAppData 83 { 84 private String sqlFile; 85 private List tokens; 86 private Token token; 87 private AppData appData; 88 private Database appDataDB; 89 private int count; 90 private String databaseType; 91 private String basePropsFilePath; 92 93 /*** 94 * Create a new class with an input Reader 95 * 96 * @param sqlFile the sql file 97 */ 98 public SQLToAppData(String sqlFile) 99 { 100 this.sqlFile = sqlFile; 101 } 102 103 /*** 104 * Create a new class with an input Reader. This ctor is not used 105 * but putting here in the event db.props properties are found to 106 * be useful converting sql to xml, the infrastructure will exist 107 * 108 * @param sqlFile the sql file 109 * @param databaseType 110 * @param basePropsFilePath 111 */ 112 public SQLToAppData(String sqlFile, String databaseType, 113 String basePropsFilePath) 114 { 115 this.sqlFile = sqlFile; 116 this.databaseType = databaseType; 117 this.basePropsFilePath = basePropsFilePath; 118 } 119 120 /*** 121 * Get the current input sql file 122 * 123 * @return the sql file 124 */ 125 public String getSqlFile() 126 { 127 return sqlFile; 128 } 129 130 /*** 131 * Set the current input sql file 132 * 133 * @param sqlFile the sql file 134 */ 135 public void setSqlFile(String sqlFile) 136 { 137 this.sqlFile = sqlFile; 138 } 139 140 /*** 141 * Move to the next token. Throws an exception 142 * if there is no more tokens available. 143 * 144 * @throws ParseException 145 */ 146 private void next() throws ParseException 147 { 148 if (count < tokens.size()) 149 { 150 token = (Token) tokens.get(count++); 151 } 152 else 153 { 154 throw new ParseException("No More Tokens"); 155 } 156 } 157 158 /*** 159 * Creates an error condition and adds the line and 160 * column number of the current token to the error 161 * message. 162 * 163 * @param name name of the error 164 * @throws ParseException 165 */ 166 private void err(String name) throws ParseException 167 { 168 throw new ParseException (name + " at [ line: " + token.getLine() 169 + " col: " + token.getCol() + " ]"); 170 } 171 172 /*** 173 * Check if there is more tokens available for parsing. 174 * 175 * @return true if there are more tokens available 176 */ 177 private boolean hasTokens() 178 { 179 return count < tokens.size(); 180 } 181 182 /*** 183 * Parses a CREATE TABLE FOO command. 184 * 185 * @throws ParseException 186 */ 187 private void create() throws ParseException 188 { 189 next(); 190 if (token.getStr().toUpperCase().equals("TABLE")) 191 { 192 create_Table(); 193 } 194 } 195 196 /*** 197 * Parses a CREATE TABLE sql command 198 * 199 * @throws ParseException error parsing the input file 200 */ 201 private void create_Table() throws ParseException 202 { 203 next(); 204 String tableName = token.getStr(); // name of the table 205 next(); 206 if (!token.getStr().equals("(")) 207 { 208 err("( expected"); 209 } 210 next(); 211 212 Table tbl = new Table (tableName); 213 //tbl.setIdMethod("none"); 214 while (!token.getStr().equals(";")) 215 { 216 create_Table_Column(tbl); 217 } 218 219 if (tbl.getPrimaryKey().size() == 1) 220 { 221 tbl.setIdMethod(IDMethod.ID_BROKER); 222 } 223 else 224 { 225 tbl.setIdMethod(IDMethod.NO_ID_METHOD); 226 } 227 appDataDB.addTable (tbl); 228 } 229 230 /*** 231 * Parses column information between the braces of a CREATE 232 * TABLE () sql statement. 233 * 234 * @throws ParseException error parsing the input file 235 */ 236 private void create_Table_Column(Table tbl) throws ParseException 237 { 238 // The token should be the first item 239 // which is the name of the column or 240 // PRIMARY/FOREIGN/UNIQUE 241 if (token.getStr().equals(",")) 242 { 243 next(); 244 } 245 246 if (token.getStr().toUpperCase().equals("PRIMARY")) 247 { 248 create_Table_Column_Primary(tbl); 249 } 250 else if (token.getStr().toUpperCase().equals("FOREIGN")) 251 { 252 create_Table_Column_Foreign(tbl); 253 } 254 else if (token.getStr().toUpperCase().equals("UNIQUE")) 255 { 256 create_Table_Column_Unique(tbl); 257 } 258 else 259 { 260 create_Table_Column_Data(tbl); 261 } 262 } 263 264 /*** 265 * Parses PRIMARY KEY (FOO,BAR) statement 266 * 267 * @throws ParseException error parsing the input file 268 */ 269 private void create_Table_Column_Primary (Table tbl) throws ParseException 270 { 271 next(); 272 if (!token.getStr().toUpperCase().equals("KEY")) 273 { 274 err("KEY expected"); 275 } 276 next(); 277 if (!token.getStr().toUpperCase().equals("(")) 278 { 279 err("( expected"); 280 } 281 next(); 282 283 String colName = token.getStr(); 284 Column c = tbl.getColumn(colName); 285 if (c == null) 286 { 287 err("Invalid column name: " + colName); 288 } 289 c.setPrimaryKey(true); 290 next(); 291 while (token.getStr().equals(",")) 292 { 293 next(); 294 colName = token.getStr(); 295 c = tbl.getColumn(colName); 296 if (c == null) 297 { 298 err("Invalid column name: " + colName); 299 } 300 c.setPrimaryKey(true); 301 next(); 302 } 303 304 if (!token.getStr().toUpperCase().equals(")")) 305 { 306 err(") expected"); 307 } 308 next(); // skip the ) 309 } 310 311 /*** 312 * Parses UNIQUE (NAME,FOO,BAR) statement 313 * 314 * @throws ParseException error parsing the input file 315 */ 316 private void create_Table_Column_Unique(Table tbl) throws ParseException 317 { 318 next(); 319 if (!token.getStr().toUpperCase().equals("(")) 320 { 321 err("( expected"); 322 } 323 next(); 324 while (!token.getStr().equals(")")) 325 { 326 if (!token.getStr().equals(",")) 327 { 328 String colName = token.getStr(); 329 Column c = tbl.getColumn(colName); 330 if (c == null) 331 { 332 err("Invalid column name: " + colName); 333 } 334 c.setUnique(true); 335 } 336 next(); 337 } 338 if (!token.getStr().toUpperCase().equals(")")) 339 { 340 err(") expected got: " + token.getStr()); 341 } 342 343 next(); // skip the ) 344 } 345 346 /*** 347 * Parses FOREIGN KEY (BAR) REFERENCES TABLE (BAR) statement 348 * 349 * @throws ParseException error parsing the input file 350 */ 351 private void create_Table_Column_Foreign(Table tbl) throws ParseException 352 { 353 next(); 354 if (!token.getStr().toUpperCase().equals("KEY")) 355 { 356 err("KEY expected"); 357 } 358 next(); 359 if (!token.getStr().toUpperCase().equals("(")) 360 { 361 err("( expected"); 362 } 363 next(); 364 365 ForeignKey fk = new ForeignKey(); 366 List localColumns = new ArrayList(); 367 tbl.addForeignKey(fk); 368 369 String colName = token.getStr(); 370 localColumns.add(colName); 371 next(); 372 while (token.getStr().equals(",")) 373 { 374 next(); 375 colName = token.getStr(); 376 localColumns.add(colName); 377 next(); 378 } 379 if (!token.getStr().toUpperCase().equals(")")) 380 { 381 err(") expected"); 382 } 383 384 next(); 385 386 if (!token.getStr().toUpperCase().equals("REFERENCES")) 387 { 388 err("REFERENCES expected"); 389 } 390 391 next(); 392 393 fk.setForeignTableName(token.getStr()); 394 395 next(); 396 397 if (token.getStr().toUpperCase().equals("(")) 398 { 399 next(); 400 int i = 0; 401 fk.addReference((String) localColumns.get(i++), token.getStr()); 402 next(); 403 while (token.getStr().equals(",")) 404 { 405 next(); 406 fk.addReference((String) localColumns.get(i++), token.getStr()); 407 next(); 408 } 409 if (!token.getStr().toUpperCase().equals(")")) 410 { 411 err(") expected"); 412 } 413 next(); 414 } 415 } 416 417 /*** 418 * Parse the data definition of the column statement. 419 * 420 * @throws ParseException error parsing the input file 421 */ 422 private void create_Table_Column_Data(Table tbl) throws ParseException 423 { 424 String columnSize = null; 425 String columnPrecision = null; 426 String columnDefault = null; 427 boolean inEnum = false; 428 429 String columnName = token.getStr(); 430 next(); 431 String columnType = token.getStr(); 432 433 if (columnName.equals(")") && columnType.equals(";")) 434 { 435 return; 436 } 437 438 next(); 439 440 // special case for MySQL ENUM's which are stupid anyway 441 // and not properly handled by Torque. 442 if (columnType.toUpperCase().equals("ENUM")) 443 { 444 inEnum = true; 445 next(); // skip ( 446 while (!token.getStr().equals(")")) 447 { 448 // skip until ) 449 next(); 450 } 451 while (!token.getStr().equals(",")) 452 { 453 if (token.getStr().toUpperCase().equals("DEFAULT")) 454 { 455 next(); 456 if (token.getStr().equals("'")) 457 { 458 next(); 459 } 460 columnDefault = token.getStr(); 461 next(); 462 if (token.getStr().equals("'")) 463 { 464 next(); 465 } 466 } 467 // skip until , 468 next(); 469 } 470 next(); // skip , 471 columnType = "VARCHAR"; 472 } 473 else if (token.getStr().toUpperCase().equals("(")) 474 { 475 next(); 476 columnSize = token.getStr(); 477 next(); 478 if (token.getStr().equals(",")) 479 { 480 next(); 481 columnPrecision = token.getStr(); 482 next(); 483 } 484 485 if (!token.getStr().equals(")")) 486 { 487 err(") expected"); 488 } 489 next(); 490 } 491 492 Column col = new Column(columnName); 493 if (columnPrecision != null) 494 { 495 columnSize = columnSize + columnPrecision; 496 } 497 col.setTypeFromString(columnType, columnSize); 498 tbl.addColumn(col); 499 500 if (inEnum) 501 { 502 col.setNotNull(true); 503 if (columnDefault != null) 504 { 505 col.setDefaultValue(columnDefault); 506 } 507 } 508 else 509 { 510 while (!token.getStr().equals(",") && !token.getStr().equals(")")) 511 { 512 if (token.getStr().toUpperCase().equals("NOT")) 513 { 514 next(); 515 if (!token.getStr().toUpperCase().equals("NULL")) 516 { 517 err("NULL expected after NOT"); 518 } 519 col.setNotNull(true); 520 next(); 521 } 522 else if (token.getStr().toUpperCase().equals("PRIMARY")) 523 { 524 next(); 525 if (!token.getStr().toUpperCase().equals("KEY")) 526 { 527 err("KEY expected after PRIMARY"); 528 } 529 col.setPrimaryKey(true); 530 next(); 531 } 532 else if (token.getStr().toUpperCase().equals("UNIQUE")) 533 { 534 col.setUnique(true); 535 next(); 536 } 537 else if (token.getStr().toUpperCase().equals("NULL")) 538 { 539 col.setNotNull(false); 540 next(); 541 } 542 else if (token.getStr().toUpperCase().equals("AUTO_INCREMENT")) 543 { 544 col.setAutoIncrement(true); 545 next(); 546 } 547 else if (token.getStr().toUpperCase().equals("DEFAULT")) 548 { 549 next(); 550 if (token.getStr().equals("'")) 551 { 552 next(); 553 } 554 col.setDefaultValue(token.getStr()); 555 next(); 556 if (token.getStr().equals("'")) 557 { 558 next(); 559 } 560 } 561 } 562 next(); // eat the , 563 } 564 } 565 566 /*** 567 * Execute the parser. 568 * 569 * @throws IOException If an I/O error occurs 570 * @throws ParseException error parsing the input file 571 */ 572 public AppData execute() throws IOException, ParseException 573 { 574 count = 0; 575 appData = new AppData(databaseType, basePropsFilePath); 576 appDataDB = new Database(); 577 appData.addDatabase(appDataDB); 578 579 FileReader fr = new FileReader(sqlFile); 580 BufferedReader br = new BufferedReader(fr); 581 SQLScanner scanner = new SQLScanner(br); 582 583 tokens = scanner.scan(); 584 585 br.close(); 586 587 while (hasTokens()) 588 { 589 if (token == null) 590 { 591 next(); 592 } 593 594 if (token.getStr().toUpperCase().equals("CREATE")) 595 { 596 create(); 597 } 598 if (hasTokens()) 599 { 600 next(); 601 } 602 } 603 return appData; 604 } 605 606 /*** 607 * Just 4 testing. 608 * 609 * @param args commandline args 610 * @throws Exception an exception 611 */ 612 public static void main(String args[]) throws Exception 613 { 614 SQLToAppData s2a = new SQLToAppData(args[0]); 615 AppData ad = s2a.execute(); 616 System.out.println(ad); 617 } 618 }

This page was automatically generated by Maven