You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jaxme-dev@ws.apache.org by jo...@apache.org on 2004/01/01 23:44:05 UTC

cvs commit: ws-jaxme/src/js/org/apache/ws/jaxme/js/pattern VersionGenerator.java

jochen      2004/01/01 14:44:05

  Modified:    src/js/org/apache/ws/jaxme/js/junit VersionTest.java
               .        buildxs.xml buildjm.xml buildjs.xml
               src/js/org/apache/ws/jaxme/sqls/junit CreateTest.java
               src/js/org/apache/ws/jaxme/js/pattern VersionGenerator.java
  Log:
  Test suite is running with haltOnFailure="yes" again.
  
  Revision  Changes    Path
  1.2       +203 -193  ws-jaxme/src/js/org/apache/ws/jaxme/js/junit/VersionTest.java
  
  Index: VersionTest.java
  ===================================================================
  RCS file: /home/cvs/ws-jaxme/src/js/org/apache/ws/jaxme/js/junit/VersionTest.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- VersionTest.java	23 Sep 2003 12:33:43 -0000	1.1
  +++ VersionTest.java	1 Jan 2004 22:44:04 -0000	1.2
  @@ -72,197 +72,207 @@
    * @author <a href="mailto:jwi@softwareag.com">Jochen Wiedmann</a>
    */
   public class VersionTest extends TestCase {
  -  private static final Logger logger = LoggerAccess.getLogger(VersionTest.class);
  -  public VersionTest(String pName) { super(pName); }
  -  private Connection connection;
  -
  -  public void tearDown() throws SQLException, ClassNotFoundException {
  -    if (connection != null) {
  -      boolean isConnClosed = false;
  -      try {
  -        Statement stmt = connection.createStatement();
  -        boolean isStmtClosed = false;
  -        try {
  -          stmt.executeUpdate("SHUTDOWN");
  -          isStmtClosed = true;
  -          stmt.close();
  -        } finally {
  -          if (!isStmtClosed) try { stmt.close(); } catch (Throwable ignore) {}
  -        }
  -        isConnClosed = true;
  -        connection.close();
  -      } catch (SQLException e) {
  -        if (e.getMessage().indexOf("The database is shutdown in statement") == -1) {
  -          throw e;
  -        }
  -      } finally {
  -        if (!isConnClosed) try { connection.close(); } catch (Throwable ignore) {} 
  -      }
  -    }
  -  }
  -
  -  private SQLFactory factory;
  -  private Schema schema;
  -  private Table mainTable, subTable, subsubTable;
  -
  -  protected SQLFactory getSQLFactory() {
  -    if (factory == null) {
  -      factory = new HsqlDbSQLFactoryImpl();
  -    }
  -    return factory;
  -  }
  -
  -  protected Table getMainTable() {
  -     if (mainTable == null) {
  -        Table mt = getSchema().newTable("MAIN");
  -        Column mtId = mt.newColumn("ID", Column.Type.BIGINT);
  -        Column mtVer = mt.newColumn("VER", Column.Type.INTEGER);
  -        StringColumn mtName = (StringColumn) mt.newColumn("NAME", Column.Type.VARCHAR);
  -        mtName.setLength(60);
  -        BinaryColumn mtSig = (BinaryColumn) mt.newColumn("SIG", Column.Type.BINARY);
  -        mtSig.setLength(16);
  -        mt.newColumn("DATE", Column.Type.DATE);
  -
  -        Index primaryKey = mt.newPrimaryKey();
  -        primaryKey.addColumn(mtId);
  -        primaryKey.addColumn(mtVer);
  -        mainTable = mt;
  -     }
  -     return mainTable;
  -  }
  -
  -  protected Table getSubTable() {
  -    if (subTable == null) {
  -      Table st = getSchema().newTable("SUB");
  -      StringColumn stId = (StringColumn) st.newColumn("ID", Column.Type.VARCHAR);
  -      stId.setLength(32);
  -
  -      Column stMtId = st.newColumn("MTID", Column.Type.BIGINT);
  -      Column stMtVer = st.newColumn("MTVER", Column.Type.INTEGER);
  -      StringColumn stAddress = (StringColumn) st.newColumn("ADDRESS", Column.Type.VARCHAR);
  -      stAddress.setLength(60);
  -      StringColumn stEmail = (StringColumn) st.newColumn("EMAIL", Column.Type.VARCHAR);
  -      stEmail.setLength(60);
  -      stEmail.setNullable(true);
  -
  -      Index primaryKey = st.newPrimaryKey();
  -      primaryKey.addColumn(stId);
  -
  -      ForeignKey foreignKey = st.newForeignKey(getMainTable());
  -      foreignKey.addColumnLink(stMtId, getMainTable().getColumn("ID"));
  -      foreignKey.addColumnLink(stMtVer, getMainTable().getColumn("VER"));
  -
  -      subTable = st;
  -    }
  -    return subTable;
  -  }
  -
  -  protected Table getSubSubTable() {
  -     if (subsubTable == null) {
  -        Table sst = getSchema().newTable("SUBSUB");
  -        StringColumn sstId = (StringColumn) sst.newColumn("ID", Column.Type.VARCHAR);
  -        sstId.setLength(32);
  -
  -        Column sstMtId = sst.newColumn("MTID", Column.Type.BIGINT);
  -        Column sstMtVer = sst.newColumn("MTVER", Column.Type.INTEGER);
  -        ForeignKey foreignKeySt = sst.newForeignKey(getMainTable());
  -        foreignKeySt.addColumnLink(sstMtId, getMainTable().getColumn("ID"));
  -        foreignKeySt.addColumnLink(sstMtVer, getMainTable().getColumn("VER"));
  -
  -        StringColumn sstStId = (StringColumn) sst.newColumn("SSTID", Column.Type.VARCHAR);
  -        sstStId.setLength(32);
  -        ForeignKey foreignKeySst = sst.newForeignKey(getSubTable());
  -        foreignKeySst.addColumnLink(sstStId, getSubTable().getColumn("ID"));
  -
  -        sst.newColumn("MTTS", Column.Type.TIMESTAMP);
  -     }
  -     return subsubTable;
  -  }
  -
  -  protected Schema getSchema() {
  -    if (schema == null) {
  -      schema = getSQLFactory().getDefaultSchema();
  -      getMainTable();
  -      getSubTable();
  -      getSubSubTable();
  -    }
  -    return schema;
  -  }
  -
  -  protected Connection getConnection() throws ClassNotFoundException, SQLException {
  -    if (connection == null) {
  -      final String mName = "getConnection";
  -      String driver = System.getProperty("jdbc.driver");
  -      if (driver == null) {
  -        driver = "org.hsqldb.jdbcDriver";
  -        logger.fine(mName, "System property 'jdbc.driver' not set, using default JDBC driver: " + driver);
  -      } else {
  -        logger.fine(mName, "Using JDBC driver: " + driver);
  -      }
  -      try {
  -        Class.forName(driver);
  -      } catch (ClassNotFoundException e) {
  -        try {
  -          Thread.currentThread().getContextClassLoader().loadClass(driver);
  -        } catch (ClassNotFoundException ex) {
  -          throw e;
  -        }
  -      }
  -
  -      String url = System.getProperty("jdbc.url");
  -      if (url == null) {
  -        url = "jdbc:hsqldb:build/db/db";
  -        logger.fine(mName, "System property 'jdbc.url' not set, using default JDBC url: " + url);
  -      } else {
  -        logger.fine(mName, "Using JDBC url: " + url);
  -      }
  -
  -      String user = System.getProperty("jdbc.user");
  -      String password;
  -      if (user == null) {
  -        user = "sa";
  -        password = "";
  -        logger.fine(mName, "System property 'jdbc.user' not set, using default JDBC user: " + user);
  -      } else {
  -        password = System.getProperty("jdbc.password");
  -        logger.fine(mName, "Using JDBC user: " + user);
  -      }
  -
  -      connection = DriverManager.getConnection(url, user, password);
  -    }
  -    return connection;
  -  }
  -
  -  private String[] stmts = new String[]{
  -    "DELETE FROM SUBSUB",
  -    "DELETE FROM SUB",
  -    "DELETE FROM MAIN",
  -    "INSERT INTO MAIN VALUES (456, 'foo Main', 1, '000102030405060708090a0b0c0d0e0f', '2003-06-09')",
  -    "INSERT INTO MAIN VALUES (456, 'foo Main 2', 22, 'a0a1a2a3a4a5a6a7a8a9aaabacadaeaf', '2003-06-10')",
  -    "INSERT INTO MAIN VALUES (457, 'bar Main', 3, 'f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff', '2003-06-10')",
  -    "INSERT INTO SUB VALUES (456, 1, 'Somewhere', '23423423', 'some@where')",
  -    "INSERT INTO SUB VALUES (456, 22, 'Somewhere', '23423434', 'some@where')",
  -    "INSERT INTO SUB VALUES (456, 22, 'Someone', '23421425', 'some@one')",
  -    "INSERT INTO SUB VALUES (457, 3, 'Somewhere', '23423426', 'some@where')",
  -    "INSERT INTO SUB VALUES (457, 3, 'Someone', '23421427', 'some@one')",
  -    "INSERT INTO SUBSUB VALUES ('324987', 456, 1, '23423423', '2003-06-10 12:00:00')",
  -    "INSERT INTO SUBSUB VALUES ('124987', 456, 22, '23423434', '2003-06-10 12:00:01')",
  -    "INSERT INTO SUBSUB VALUES ('124988', 456, 22, '23423434', '2003-06-10 12:00:02')",
  -    "INSERT INTO SUBSUB VALUES ('124989', 456, 22, '23421425', '2003-06-10 12:00:03')",
  -    "INSERT INTO SUBSUB VALUES ('124990', 457, 3, '23423426', '2003-06-10 12:00:04')",
  -    "INSERT INTO SUBSUB VALUES ('124991', 457, 3, '23421427', '2003-06-10 12:00:04')"
  -
  -  };
  -
  -  public void testClone() throws SQLException, ClassNotFoundException {
  -     Connection conn = getConnection();
  -     for (int i = 0;  i < stmts.length;  i++) {
  -       PreparedStatement stmt = conn.prepareStatement(stmts[i]);
  -       stmt.executeUpdate();
  -     }
  -     Object[] values = new Object[]{new Long(456), new Integer(1)};
  -     Object[] updatedValues = (new MAINCloner()).clone(conn, values);
  -     assertEquals(456, ((Long) updatedValues[0]).longValue());
  -     assertEquals(2, ((Integer) updatedValues[2]).intValue());
  -  }
  +	private static final Logger logger = LoggerAccess.getLogger(VersionTest.class);
  +	public VersionTest(String pName) { super(pName); }
  +	private Connection connection;
  +	
  +	public void tearDown() throws SQLException, ClassNotFoundException {
  +		if (connection != null) {
  +			boolean isConnClosed = false;
  +			try {
  +				Statement stmt = connection.createStatement();
  +				boolean isStmtClosed = false;
  +				try {
  +					stmt.executeUpdate("SHUTDOWN");
  +					isStmtClosed = true;
  +					stmt.close();
  +				} finally {
  +					if (!isStmtClosed) try { stmt.close(); } catch (Throwable ignore) {}
  +				}
  +				isConnClosed = true;
  +				connection.close();
  +			} catch (SQLException e) {
  +				if (e.getMessage().indexOf("The database is shutdown in statement") == -1) {
  +					throw e;
  +				}
  +			} finally {
  +				if (!isConnClosed) try { connection.close(); } catch (Throwable ignore) {} 
  +			}
  +		}
  +	}
  +	
  +	private SQLFactory factory;
  +	private Schema schema;
  +	private Table mainTable, subTable, subsubTable;
  +	
  +	protected SQLFactory getSQLFactory() {
  +		if (factory == null) {
  +			factory = new HsqlDbSQLFactoryImpl();
  +		}
  +		return factory;
  +	}
  +	
  +	protected Table getMainTable() {
  +		if (mainTable == null) {
  +			Table mt = getSchema().newTable("MAIN");
  +			Column mtId = mt.newColumn("ID", Column.Type.BIGINT);
  +			Column mtVer = mt.newColumn("VER", Column.Type.INTEGER);
  +			StringColumn mtName = (StringColumn) mt.newColumn("NAME", Column.Type.VARCHAR);
  +			mtName.setLength(60);
  +			BinaryColumn mtSig = (BinaryColumn) mt.newColumn("SIG", Column.Type.BINARY);
  +			mtSig.setLength(16);
  +			mt.newColumn("DATE", Column.Type.DATE);
  +			
  +			Index primaryKey = mt.newPrimaryKey();
  +			primaryKey.addColumn(mtId);
  +			primaryKey.addColumn(mtVer);
  +			mainTable = mt;
  +		}
  +		return mainTable;
  +	}
  +	
  +	protected Table getSubTable() {
  +		if (subTable == null) {
  +			Table st = getSchema().newTable("SUB");
  +			StringColumn stId = (StringColumn) st.newColumn("ID", Column.Type.VARCHAR);
  +			stId.setLength(32);
  +			
  +			Column stMtId = st.newColumn("MTID", Column.Type.BIGINT);
  +			Column stMtVer = st.newColumn("MTVER", Column.Type.INTEGER);
  +			StringColumn stAddress = (StringColumn) st.newColumn("ADDRESS", Column.Type.VARCHAR);
  +			stAddress.setLength(60);
  +			StringColumn stEmail = (StringColumn) st.newColumn("EMAIL", Column.Type.VARCHAR);
  +			stEmail.setLength(60);
  +			stEmail.setNullable(true);
  +			
  +			Index primaryKey = st.newPrimaryKey();
  +			primaryKey.addColumn(stId);
  +			
  +			ForeignKey foreignKey = st.newForeignKey(getMainTable());
  +			foreignKey.addColumnLink(stMtId, getMainTable().getColumn("ID"));
  +			foreignKey.addColumnLink(stMtVer, getMainTable().getColumn("VER"));
  +			
  +			subTable = st;
  +		}
  +		return subTable;
  +	}
  +	
  +	protected Table getSubSubTable() {
  +		if (subsubTable == null) {
  +			Table sst = getSchema().newTable("SUBSUB");
  +			StringColumn sstId = (StringColumn) sst.newColumn("ID", Column.Type.VARCHAR);
  +			sstId.setLength(32);
  +			
  +			Column sstMtId = sst.newColumn("MTID", Column.Type.BIGINT);
  +			Column sstMtVer = sst.newColumn("MTVER", Column.Type.INTEGER);
  +			ForeignKey foreignKeySt = sst.newForeignKey(getMainTable());
  +			foreignKeySt.addColumnLink(sstMtId, getMainTable().getColumn("ID"));
  +			foreignKeySt.addColumnLink(sstMtVer, getMainTable().getColumn("VER"));
  +			
  +			StringColumn sstStId = (StringColumn) sst.newColumn("SSTID", Column.Type.VARCHAR);
  +			sstStId.setLength(32);
  +			ForeignKey foreignKeySst = sst.newForeignKey(getSubTable());
  +			foreignKeySst.addColumnLink(sstStId, getSubTable().getColumn("ID"));
  +			
  +			sst.newColumn("MTTS", Column.Type.TIMESTAMP);
  +		}
  +		return subsubTable;
  +	}
  +	
  +	protected Schema getSchema() {
  +		if (schema == null) {
  +			schema = getSQLFactory().getDefaultSchema();
  +			getMainTable();
  +			getSubTable();
  +			getSubSubTable();
  +		}
  +		return schema;
  +	}
  +	
  +	protected Connection getConnection() throws ClassNotFoundException, SQLException {
  +		if (connection == null) {
  +			final String mName = "getConnection";
  +			String driver = System.getProperty("jdbc.driver");
  +			if (driver == null) {
  +				driver = "org.hsqldb.jdbcDriver";
  +				logger.fine(mName, "System property 'jdbc.driver' not set, using default JDBC driver: " + driver);
  +			} else {
  +				logger.fine(mName, "Using JDBC driver: " + driver);
  +			}
  +			try {
  +				Class.forName(driver);
  +			} catch (ClassNotFoundException e) {
  +				try {
  +					Thread.currentThread().getContextClassLoader().loadClass(driver);
  +				} catch (ClassNotFoundException ex) {
  +					throw e;
  +				}
  +			}
  +			
  +			String url = System.getProperty("jdbc.url");
  +			if (url == null) {
  +				url = "jdbc:hsqldb:build/db/db";
  +				logger.fine(mName, "System property 'jdbc.url' not set, using default JDBC url: " + url);
  +			} else {
  +				logger.fine(mName, "Using JDBC url: " + url);
  +			}
  +			
  +			String user = System.getProperty("jdbc.user");
  +			String password;
  +			if (user == null) {
  +				user = "sa";
  +				password = "";
  +				logger.fine(mName, "System property 'jdbc.user' not set, using default JDBC user: " + user);
  +			} else {
  +				password = System.getProperty("jdbc.password");
  +				logger.fine(mName, "Using JDBC user: " + user);
  +			}
  +			
  +			connection = DriverManager.getConnection(url, user, password);
  +		}
  +		return connection;
  +	}
  +	
  +	private String[] stmts = new String[] {
  +		"DELETE FROM SUBSUB",
  +		"DELETE FROM SUB",
  +		"DELETE FROM MAIN",
  +		"INSERT INTO MAIN VALUES (456, 'foo Main', 1, '000102030405060708090a0b0c0d0e0f', '2003-06-09')",
  +		"INSERT INTO MAIN VALUES (456, 'foo Main 2', 22, 'a0a1a2a3a4a5a6a7a8a9aaabacadaeaf', '2003-06-10')",
  +		"INSERT INTO MAIN VALUES (457, 'bar Main', 3, 'f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff', '2003-06-10')",
  +		"INSERT INTO SUB VALUES (456, 1, 'Somewhere', '23423423', 'some@where')",
  +		"INSERT INTO SUB VALUES (456, 22, 'Somewhere', '23423434', 'some@where')",
  +		"INSERT INTO SUB VALUES (456, 22, 'Someone', '23421425', 'some@one')",
  +		"INSERT INTO SUB VALUES (457, 3, 'Somewhere', '23423426', 'some@where')",
  +		"INSERT INTO SUB VALUES (457, 3, 'Someone', '23421427', 'some@one')",
  +		"INSERT INTO SUBSUB VALUES ('324987', 456, 1, '23423423', '2003-06-10 12:00:00')",
  +		"INSERT INTO SUBSUB VALUES ('124987', 456, 22, '23423434', '2003-06-10 12:00:01')",
  +		"INSERT INTO SUBSUB VALUES ('124988', 456, 22, '23423434', '2003-06-10 12:00:02')",
  +		"INSERT INTO SUBSUB VALUES ('124989', 456, 22, '23421425', '2003-06-10 12:00:03')",
  +		"INSERT INTO SUBSUB VALUES ('124990', 457, 3, '23423426', '2003-06-10 12:00:04')",
  +		"INSERT INTO SUBSUB VALUES ('124991', 457, 3, '23421427', '2003-06-10 12:00:04')"
  +	};
  +	
  +	public void testCreate() throws ClassNotFoundException, SQLException {
  +		Connection conn = getConnection();
  +		for (int i = 0;  i < stmts.length;  i++) {
  +			PreparedStatement stmt = conn.prepareStatement(stmts[i]);
  +			try {
  +				stmt.executeUpdate();
  +			} catch (SQLException e) {
  +				if (stmts[i].startsWith("DROP TABLE ")  &&  "S0002".equals(e.getSQLState())) {
  +					continue;
  +				}
  +				throw e;
  +			}
  +		}
  +	}
  +	
  +	public void testClone() throws SQLException, ClassNotFoundException {
  +		Connection conn = getConnection();
  +		Object[] values = new Object[]{new Long(456), new Integer(1)};
  +		Object[] updatedValues = (new MAINCloner()).clone(conn, values);
  +		assertEquals(456, ((Long) updatedValues[0]).longValue());
  +		assertEquals(2, ((Integer) updatedValues[2]).intValue());
  +	}
   }
  
  
  
  1.6       +3 -2      ws-jaxme/buildxs.xml
  
  Index: buildxs.xml
  ===================================================================
  RCS file: /home/cvs/ws-jaxme/buildxs.xml,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- buildxs.xml	1 Jan 2004 17:51:00 -0000	1.5
  +++ buildxs.xml	1 Jan 2004 22:44:04 -0000	1.6
  @@ -47,14 +47,15 @@
   
     <target name="test" depends="init.clover,init,all">
       <mkdir dir="${build.reports}"/>
  -    <junit printsummary="yes" haltonfailure="no">
  +    <junit printsummary="yes" haltonfailure="yes">
         <classpath>
           <path refid="jaxmexs.class.path"/>
           <pathelement location="${dist}/jaxmexs.jar"/>
         </classpath>
         <formatter type="plain" />
         <batchtest todir="${build.reports}">
  -        <fileset dir="${src}" includes="org/apache/ws/jaxme/xs/junit/**/*Test.java"/>
  +        <fileset dir="${src}" includes="org/apache/ws/jaxme/xs/junit/**/*Test.java"
  +        	                  excludes="org/apache/ws/jaxme/xs/junit/WSDLTest.java"/>
         </batchtest>
       </junit>
     </target>
  
  
  
  1.5       +1 -1      ws-jaxme/buildjm.xml
  
  Index: buildjm.xml
  ===================================================================
  RCS file: /home/cvs/ws-jaxme/buildjm.xml,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- buildjm.xml	1 Jan 2004 17:51:00 -0000	1.4
  +++ buildjm.xml	1 Jan 2004 22:44:04 -0000	1.5
  @@ -288,7 +288,7 @@
         </classpath>
         <include name="org/apache/ws/jaxme/junit/*Test.java"/>
       </javac>
  -    <junit printsummary="yes" haltonfailure="no">
  +    <junit printsummary="yes" haltonfailure="yes">
         <classpath>
           <path refid="jaxme.runtime.path"/>
           <pathelement location="${build}/classes"/>
  
  
  
  1.3       +4 -4      ws-jaxme/buildjs.xml
  
  Index: buildjs.xml
  ===================================================================
  RCS file: /home/cvs/ws-jaxme/buildjs.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- buildjs.xml	1 Jan 2004 17:51:00 -0000	1.2
  +++ buildjs.xml	1 Jan 2004 22:44:04 -0000	1.3
  @@ -119,12 +119,12 @@
     <target name="generate.db" depends="init,check.db" unless="exists.db">
   	<delete dir="${build.db}"/>
       <mkdir dir="${build.db}"/>
  -    <sql  
  +    <sql
           src="${src}/org/apache/ws/jaxme/js/junit/create.sql"
           driver="${jdbc.driver}"
           url="${jdbc.url}"
           userid="${jdbc.user}"
  -        password="${jdbc.password}"
  +        password="${jdbc.password}" 
           classpathref="jaxmejs.runtime.path"/>
     </target>
   
  @@ -159,7 +159,7 @@
   
     <target name="test.javasource" depends="all">
       <mkdir dir="${build.reports}"/>
  -    <junit printsummary="yes" haltonfailure="no">
  +    <junit printsummary="yes" haltonfailure="yes">
         <classpath>
           <path refid="jaxmejs.runtime.path"/>
           <pathelement location="${build.test.classes}"/>
  @@ -179,7 +179,7 @@
   
     <target name="test.sqlsource" depends="all">
       <mkdir dir="${build.reports}"/>
  -    <junit printsummary="yes" haltonfailure="no">
  +    <junit printsummary="yes" haltonfailure="yes">
         <classpath>
           <path refid="jaxmejs.runtime.path"/>
           <pathelement location="${build.test.classes}"/>
  
  
  
  1.5       +1 -1      ws-jaxme/src/js/org/apache/ws/jaxme/sqls/junit/CreateTest.java
  
  Index: CreateTest.java
  ===================================================================
  RCS file: /home/cvs/ws-jaxme/src/js/org/apache/ws/jaxme/sqls/junit/CreateTest.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- CreateTest.java	5 Dec 2003 09:45:20 -0000	1.4
  +++ CreateTest.java	1 Jan 2004 22:44:05 -0000	1.5
  @@ -392,7 +392,7 @@
       BooleanConstraint bc = deleteStatement.getWhere().createIN();
       bc.addPart((ColumnReference[]) columns.toArray(new ColumnReference[columns.size()]));
       bc.addPart(selectStatement);
  -    String expect = "DELETE FROM MySchema.MyTable WHERE (MyIndex, VerNum) IN (SELECT RefMyIndex, RefVerNum FROM MySchema.OtherTable WHERE RefMyName=?)";
  +    String expect = "DELETE FROM MySchema.MyTable WHERE (MyIndex, VerNum) IN ((SELECT RefMyIndex, RefVerNum FROM MySchema.OtherTable WHERE RefMyName=?))";
       String got = gen.getQuery(deleteStatement);
       assertEquals(expect, got);
     }
  
  
  
  1.3       +917 -917  ws-jaxme/src/js/org/apache/ws/jaxme/js/pattern/VersionGenerator.java
  
  Index: VersionGenerator.java
  ===================================================================
  RCS file: /home/cvs/ws-jaxme/src/js/org/apache/ws/jaxme/js/pattern/VersionGenerator.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- VersionGenerator.java	14 Oct 2003 07:10:15 -0000	1.2
  +++ VersionGenerator.java	1 Jan 2004 22:44:05 -0000	1.3
  @@ -101,921 +101,921 @@
    * @author <a href="mailto:joe@ispsoft.de">Jochen Wiedmann</a>
    */
   public class VersionGenerator {
  -  /** <p>The ColumnUpdater is able to update one or more columns in a
  -   * table. Such a column update is required, because the cloned tables
  -   * must not have the same primary key.</p>
  -   * <p>The typical use is to specify a ColumnUpdater for the head
  -   * table, which bumps the version number. For any child table
  -   * you could specify a ColumnUpdater which generates a new primary
  -   * key.</p>
  -   */
  -  public interface ColumnUpdater {
  -    /** <p>Generates code for updating a table row. The row is supplied
  -     * as an array of objects. The order of objects matches the columns
  -     * of the given table.</p>
  -     * @param pMethod The method being created; may be used to generate
  -     *   local fields, etc.
  -     * @param pTableInfo The table being updated
  -     * @param pMap A local Java field with a Map of rows, that have already
  -     *   been cloned. The keys and values are both instances of the generated
  -     *   inner class DataCache. The keys are holding the primary keys of
  -     *   the original rows (which have been cloned) and the values are the
  -     *   primary keys of the created rows (the generated clones).
  -     * @param pConnection A local Java field with an open database connection
  -     * @param pRow A local Java field with an array of values being cloned
  -     */
  -    public void update(JavaMethod pMethod, TableInfo pTableInfo,
  -                       DirectAccessible pConnection,
  -                       DirectAccessible pMap,
  -                       DirectAccessible pRow);
  -  }
  -
  -  /** <p>This class is used internally to maintain the informations on
  -   * the tables being cloned.</p>
  -   */
  -  public static class TableInfo {
  -    private final Table table;
  -    private final String propertyName;
  -    private boolean isReferenced;
  -    private boolean hasPrimaryKey;
  -    private final List columnUpdaters = new ArrayList();
  -    TableInfo(Table pTable, String pPropertyName) {
  -      table = pTable;
  -      propertyName = pPropertyName;
  -    }
  -    public Table getTable() { return table; }
  -    public String getPropertyName() { return propertyName; }
  -    public void add(ColumnUpdater pColumnUpdater) {
  -      columnUpdaters.add(pColumnUpdater);
  -    }
  -    public Iterator getColumnUpdaters() { return columnUpdaters.iterator(); }
  -
  -    public void setReferenced(boolean pReferenced) {
  -      isReferenced = true;
  -    }
  -    public boolean isReferenced() {
  -      return isReferenced;
  -    }
  -    public boolean hasPrimaryKey() {
  -       return hasPrimaryKey;
  -    }
  -    public void setPrimaryKey(boolean pPrimaryKey) {
  -       hasPrimaryKey  = pPrimaryKey;
  -    }
  -  }
  -
  -  /** <p>An implementation of {@link ColumnUpdater}, which updates foreign
  -   * key references.</p>
  -   */
  -  private class ForeignKeyUpdater implements ColumnUpdater {
  -    private final ForeignKey foreignKey;
  -    private final TableInfo referencedTable;
  -
  -    private ForeignKeyUpdater(ForeignKey pForeignKey, TableInfo pReferencedTable) {
  -      foreignKey = pForeignKey;
  -      referencedTable = pReferencedTable;
  -    }
  -
  -    public void update(JavaMethod pMethod, TableInfo pTableInfo,
  -                       DirectAccessible pConnection,
  -                       DirectAccessible pMap, DirectAccessible pRow) {
  -      LocalJavaField referencedKey = getCacheDataClassInstance(pMethod,
  -                                                               referencedTable,
  -                                                               foreignKey, pRow);
  -      LocalJavaField mappedKey = pMethod.newJavaField(referencedKey.getType());
  -      mappedKey.addLine("(", referencedKey.getType(), ") ", pMap, ".get(",
  -                        referencedKey, ")");
  -      pMethod.addIf(mappedKey, " == null");
  -      pMethod.addThrowNew(IllegalStateException.class,
  -                          JavaSource.getQuoted("Unknown reference: "), " + ",
  -                          referencedKey);
  -      pMethod.addEndIf();
  -      int valNum = 0;
  -      for (Iterator iter = referencedTable.getTable().getPrimaryKey().getColumns();  iter.hasNext();  ) {
  -        Column referencedKeyColumn = (Column) iter.next();
  -        Column localColumn = null;
  -        for (Iterator iter2 = foreignKey.getColumnLinks();  iter2.hasNext();  ) {
  -          ForeignKey.ColumnLink link = (ForeignKey.ColumnLink) iter2.next();
  -          if (link.getReferencedColumn().equals(referencedKeyColumn)) {
  -            localColumn = link.getLocalColumn();
  -            break;
  -          }
  -        }
  -        if (localColumn == null) {
  -          throw new IllegalStateException("Unable to find the column referencing " + referencedKeyColumn.getQName());
  -        }
  -
  -        int colNum = -1, i = 0;
  -        for (Iterator iter2 = pTableInfo.getTable().getColumns();  iter2.hasNext();  ) {
  -           Column col = (Column) iter2.next();
  -           if (col.equals(localColumn)) {
  -              colNum = i;
  -              break;
  -           }
  -           ++i;
  -        }
  -        if (colNum == -1) {
  -           throw new IllegalStateException("Unable to find the column " + localColumn.getQName() + " in table " + pTableInfo.getTable().getQName());
  -        }
  -        pMethod.addLine(pRow, "[" + colNum + "] = ", mappedKey, ".getValues()[" + valNum + "];");
  -      }
  -    }
  -  }
  -
  -  private List tablesByOrder = new ArrayList();
  -  private Map tablesByName = new HashMap();
  -  private Set propertyNames = new HashSet();
  -  private boolean generatingLogging;
  -
  -  private boolean isReferencing(Table pReferencingTable, Table pReferencedTable) {
  -     for (Iterator iter = pReferencingTable.getForeignKeys();  iter.hasNext();  ) {
  -       ForeignKey foreignKey = (ForeignKey) iter.next();
  -       if (foreignKey.getReferencedTable().equals(pReferencedTable)) {
  -          return true;
  -       }
  -     }
  -     return false;
  -  }
  -
  -  /** <p>Returns whether the generator is creating logging statements. By default
  -   * no logging statements are created.</p>
  -   * <p>The default
  -   * implementation creates logging statements suitable for the JaxMe logging
  -   * package. To change this, create a subclass and overwrite the following
  -   * methods: {@link #logEntering(JavaMethod, Object)},
  -   * {@link #logExiting(JavaMethod, Object)}, {@link #logFinest(JavaMethod, Object, Object)},
  -   * {@link #logFinestEntering(JavaMethod, Object)}, and
  -   * {@link #logFinestExiting(JavaMethod, Object)}.</p>
  -   * @see #setGeneratingLogging(boolean)
  -   */
  -  public boolean isGeneratingLogging() {
  -    return generatingLogging;
  -  }
  -
  -  /** <p>Sets whether the generator is creating logging statements. By default
  -   * no logging statements are created.</p>
  -   * <p>The default
  -   * implementation creates logging statements suitable for the JaxMe logging
  -   * package. To change this, create a subclass and overwrite the following
  -   * methods: {@link #logEntering(JavaMethod, Object)},
  -   * {@link #logExiting(JavaMethod, Object)}, {@link #logFinest(JavaMethod, Object, Object)},
  -   * {@link #logFinestEntering(JavaMethod, Object)}, and
  -   * {@link #logFinestExiting(JavaMethod, Object)}.</p>
  -   * @see #isGeneratingLogging()
  -   */
  -  public void setGeneratingLogging(boolean pGeneratingLogging) {
  -    generatingLogging = pGeneratingLogging;
  -  }
  -
  -  /** <p>Creates the code for initialization of the logging framework.
  -   * The default implementation generates code creating an instance of
  -   * {@link org.apache.ws.jaxme.logging.Logger}.</p>
  -   */
  -  protected void initLogging(JavaSource pSource) {
  -    if (isGeneratingLogging()) {
  -      JavaField jf = pSource.newJavaField("logger", Logger.class, JavaSource.PRIVATE);
  -      jf.setFinal(true);
  -      jf.setStatic(true);
  -      jf.addLine(LoggerAccess.class, ".getLogger(", pSource.getQName(), ".class)");
  -    }
  -  }
  -
  -  /** <p>Creates code for logging the entrance into a method with
  -   * fine level.</p>
  -   * <p><em>Note:</em> The method should consider the {@link #isGeneratingLogging()}
  -   * value.</p>
  -   *
  -   * @param pMethod The method in which a logging statement should be inserted
  -   * @param pValues An array of additional values, possibly null
  -   */
  -  protected void logEntering(JavaMethod pMethod, Object pValues) {
  -    if (isGeneratingLogging()) {
  -      LocalJavaField mName = pMethod.newJavaField(String.class, "mName");
  -      mName.addLine(JavaSource.getQuoted(pMethod.getLoggingSignature()));
  -      mName.setFinal(true);
  -      if (pValues == null) {
  -        pMethod.addLine("logger.entering(", mName, ");");
  -      } else {
  -        pMethod.addLine("logger.entering(", mName, ", ", pValues, ");");         
  -      }
  -    }
  -  }
  -
  -  /** <p>Creates code for logging the entrance into a method with
  -   * finest level.</p>
  -   * <p><em>Note:</em> The method should consider the {@link #isGeneratingLogging()}
  -   * value.</p>
  -   * <p><em>Implementation note:</em> The default implementation is
  -   * equivalent to <code>logFinest(pMethod, "->", pValues)</code>.</p>
  -    *
  -    * @param pMethod The method in which a logging statement should be inserted
  -    * @param pValues An array of additional values, possibly null
  -   */
  -  protected void logFinestEntering(JavaMethod pMethod, Object pValues) {
  -    if (isGeneratingLogging()) {
  -      LocalJavaField mName = pMethod.newJavaField(String.class, "mName");
  -      mName.addLine(JavaSource.getQuoted(pMethod.getLoggingSignature()));
  -      mName.setFinal(true);
  -      logFinest(pMethod, JavaSource.getQuoted("->"), pValues);
  -    }
  -  }
  -
  -  /** <p>Creates code for logging the exit from a method with
  -   * fine level.</p>
  -   * <p><em>Note:</em> The method should consider the {@link #isGeneratingLogging()}
  -   * value.</p>
  -    *
  -    * @param pMethod The method in which a logging statement should be inserted
  -    * @param pValues An array of additional values, possibly null
  -   */
  -  protected void logExiting(JavaMethod pMethod, Object pValues) {
  -    if (isGeneratingLogging()) {
  -      if (pValues == null) {
  -        pMethod.addLine("logger.exiting(mName);");
  -      } else {
  -        pMethod.addLine("logger.exiting(mName, ", pValues, ");");        
  -      }
  -    }
  -  }
  -
  -  /** <p>Creates code for logging the exit from a method with
  -   * fine level.</p>
  -   * <p><em>Note:</em> The method should consider the {@link #isGeneratingLogging()}
  -   * value.</p>
  -   * <p><em>Implementation note:</em> The default implementation is
  -   * equivalent to <code>logFinest(pMethod, "<-", pValues)</code>.</p>
  -   *
  -   * @param pMethod The method in which a logging statement should be inserted
  -   * @param pValues An array of additional values, possibly null
  -   */
  -  protected void logFinestExiting(JavaMethod pMethod, Object pValues) {
  -    logFinest(pMethod, JavaSource.getQuoted("->"), pValues);
  -  }
  -
  -  /** <p>Creates code for logging a message with finest level.</p>
  -   * <p><em>Note:</em> The method should consider the {@link #isGeneratingLogging()}
  -   * value.</p>
  -   *
  -   * @param pMethod The method in which a logging statement should be inserted
  -   * @param pMsg The message being logged
  -   * @param pValues An array of additional values, possibly null
  -   */
  -  protected void logFinest(JavaMethod pMethod, Object pMsg, Object pValues) {
  -    if (isGeneratingLogging()) {
  -      if (pValues == null) {
  -        pMethod.addLine("logger.finest(mName, ", pMsg, ");");
  -      } else {
  -        pMethod.addLine("logger.finest(mName, ", pMsg, ", ", pValues, ");");
  -      }
  -    }
  -  }
  -
  -  /** Adds a new table to the list of tables. The table must not
  -   * contain a forward reference. Additionally, the table must not
  -   * be referenced by any other table, which has already been added
  -   * to the list.</p>
  -   * @param pTable The table being cloned
  -   * @param pUpdater The column updater to use for changing the
  -   *   updated columns.
  -   */
  -  public void addTable(Table pTable, ColumnUpdater pUpdater) {
  -    String name = pTable.getQName();
  -    if (tablesByName.containsKey(pTable)) {
  -      throw new IllegalStateException("A table " + name + " has already been added.");
  -    }
  -    if (isReferencing(pTable, pTable)) {
  -      throw new IllegalStateException("The table " + name + " is containing self references.");
  -    }
  -    for (Iterator iter = tablesByOrder.iterator();  iter.hasNext();  ) {
  -      TableInfo tableInfo = (TableInfo) iter.next();
  -      if (isReferencing(tableInfo.getTable(), pTable)) {
  -        throw new IllegalStateException("The table " + tableInfo.getTable().getQName() +
  -                                        " contains a forward reference to the table " + name + ".");
  -      }
  -    }
  -
  -    String s = pTable.getName().getName();
  -    String t = s;
  -    int num = 0;
  -    for (;;) {
  -      t = Character.toUpperCase(t.charAt(0)) + t.substring(1);
  -      if (!propertyNames.contains(t)) {
  -        break;
  -      }
  -      t = s + num++;
  -    }
  -    propertyNames.add(t);
  -
  -    TableInfo tableInfo = new TableInfo(pTable, t);
  -    tableInfo.setPrimaryKey(pTable.getPrimaryKey() != null);
  -    if (pUpdater != null) {
  -      tableInfo.add(pUpdater);
  -    }
  -
  -    for (Iterator iter = pTable.getForeignKeys();  iter.hasNext();  ) {
  -      ForeignKey foreignKey = (ForeignKey) iter.next();
  -      Table referencedTable = foreignKey.getReferencedTable();
  -      for (Iterator iter2 = tablesByOrder.iterator();  iter2.hasNext();  ) {
  -        TableInfo referencedTableInfo = (TableInfo) iter2.next();
  -        if (referencedTableInfo.getTable().equals(referencedTable)) {
  -          ColumnUpdater columnUpdater = new ForeignKeyUpdater(foreignKey, referencedTableInfo);
  -          tableInfo.add(columnUpdater);
  -          if (!referencedTableInfo.hasPrimaryKey()) {
  -             throw new IllegalStateException("The table " + pTable.getQName() +
  -                                             " is referencing table " + referencedTable.getQName() +
  -                                             ", which doesn't have a primary key.");
  -          }
  -          referencedTableInfo.setReferenced(true);
  -        }
  -      }
  -    }
  -
  -    tablesByName.put(name, tableInfo);
  -    tablesByOrder.add(tableInfo);
  -  }
  -
  -  /** <p>Returns the name of the inner class CacheData.</p>
  -   */
  -  protected JavaQName getCacheDataClassName(JavaQName pQName) {
  -    return JavaQNameImpl.getInnerInstance(pQName, "CacheData");
  -  }
  -
  -  /** <p>Generates the innner class CacheData.</p>
  -   */
  -  protected JavaInnerClass getCacheDataClass(JavaSource pSource) {
  -     JavaInnerClass jic = pSource.newJavaInnerClass("CacheData", JavaSource.PRIVATE);
  -
  -     JavaField name = jic.newJavaField("name", String.class, JavaSource.PRIVATE);
  -     name.setFinal(true);
  -     JavaField values = jic.newJavaField("values", Object[].class, JavaSource.PRIVATE);
  -     values.setFinal(true);
  -
  -     JavaConstructor jcon = jic.newJavaConstructor(JavaSource.PRIVATE);
  -     DirectAccessible pName = jcon.addParam(String.class, "pName");
  -     DirectAccessible pValues = jcon.addParam(Object[].class, "pValues");
  -     jcon.addLine(name, " = ", pName, ";");
  -     jcon.addLine(values, " = ", pValues, ";");
  -
  -     JavaMethod getNameMethod = jic.newJavaMethod("getName", String.class, JavaSource.PUBLIC);
  -     getNameMethod.addLine("return ", name, ";");
  -
  -     JavaMethod getValuesMethod = jic.newJavaMethod("getValues", Object[].class, JavaSource.PUBLIC);
  -     getValuesMethod.addLine("return ", values, ";");
  -
  -     {
  -       JavaMethod jm = jic.newJavaMethod("toString", String.class, JavaSource.PUBLIC);
  -       LocalJavaField sb = jm.newJavaField(StringBuffer.class, "sb");
  -       sb.addLine("new ", StringBuffer.class, "(", name, ")");
  -       DirectAccessible loopVar = jm.addForArray(values);
  -       jm.addLine(sb, ".append(", JavaSource.getQuoted(", "), ").append(",
  -                  values, "[", loopVar, "]);");
  -       jm.addEndFor();
  -       jm.addLine("return ", sb, ".toString();");
  -
  -     }
  -
  -     {
  -       JavaMethod jm = jic.newJavaMethod("hashCode", int.class, JavaSource.PUBLIC);
  -       LocalJavaField hashCodeResult = jm.newJavaField(int.class, "result");
  -       hashCodeResult.addLine(name, ".hashCode() + ", values, ".length;");
  -       DirectAccessible loopVar = jm.addForArray(values);
  -       LocalJavaField o = jm.newJavaField(Object.class, "o");
  -       o.addLine(values, "[", loopVar, "]");
  -       jm.addIf(o, " != null");
  -       jm.addLine(hashCodeResult, " += ", o, ".hashCode();");
  -       jm.addEndIf();
  -       jm.addEndFor();
  -       jm.addLine("return ", hashCodeResult, ";");
  -     }
  -
  -     {
  -       JavaMethod jm = jic.newJavaMethod("equals", boolean.class, JavaSource.PUBLIC);
  -       DirectAccessible o = jm.addParam(Object.class, "o");
  -       jm.addIf(o, " == null  ||  !(", o, " instanceof ", jic.getQName(), ")");
  -       jm.addLine("return false;");
  -       jm.addEndIf();
  -       LocalJavaField other = jm.newJavaField(jic.getQName(), "other");
  -       other.addLine("(", jic.getQName(), ") ", o);
  -       jm.addIf("!", name, ".equals(", other, ".name)  ||  ", values, ".length != ",
  -                other, ".values.length");
  -       jm.addLine("return false;");
  -       jm.addEndIf();
  -       DirectAccessible loopVar = jm.addForArray(values);
  -       LocalJavaField v = jm.newJavaField(Object.class, "v");
  -       v.addLine(values, "[", loopVar, "]");
  -       jm.addIf(v, " == null");
  -       jm.addIf(other, ".values[", loopVar, "] != null");
  -       jm.addLine("return false;");
  -       jm.addEndIf();
  -       jm.addElse();
  -       jm.addIf("!", v, ".equals(", other, ".values[", loopVar, "])");
  -       jm.addLine("return false;");
  -       jm.addEndIf();
  -       jm.addEndIf();
  -       jm.addEndFor();
  -       jm.addLine("return true;");
  -     }
  -
  -     return jic;
  -  }
  -
  -  /** <p>Generates code for reading a ResultSet's column.</p>
  -   */
  -  protected void setResultSetValue(JavaMethod pMethod, Column pColumn,
  -                                   DirectAccessible pResultSet,
  -                                   int pColumnNum, Object pTarget) {
  -    Integer p = new Integer(pColumnNum+1);
  -
  -    Column.Type type = pColumn.getType();
  -    if (Column.Type.BIGINT.equals(type)) {
  -      LocalJavaField l = pMethod.newJavaField(long.class);
  -      l.addLine(pResultSet, ".getLong(", p, ");");
  -      pMethod.addIf("!", pResultSet, ".wasNull()");
  -      pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = new ",
  -                      Long.class, "(", l, ");");
  -      pMethod.addEndIf();
  -    } else if (pColumn.isBinaryColumn()) {
  -      pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = ",
  -                      pResultSet, ".getBytes(", p, ");");
  -    } else if (Column.Type.BIT.equals(type)) {
  -      LocalJavaField b = pMethod.newJavaField(boolean.class);
  -      b.addLine(pResultSet, ".getBoolean(", p, ");");
  -      pMethod.addIf("!", pResultSet, ".wasNull()");
  -      pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = ", b,
  -                      " ? ", Boolean.class, ".TRUE : ", Boolean.class, ".FALSE;");
  -      pMethod.addEndIf();
  -    } else if (pColumn.isStringColumn()) {
  -      pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = ",
  -                      pResultSet, ".getString(", p, ");");
  -    } else if (Column.Type.DATE.equals(type)) {
  -       pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = ",
  -                       pResultSet, ".getDate(", p, ");");
  -    } else if (Column.Type.DOUBLE.equals(type)) {
  -       LocalJavaField d = pMethod.newJavaField(double.class);
  -       d.addLine(pResultSet, ".getDouble(", p, ");");
  -       pMethod.addIf("!", pResultSet, ".wasNull()");
  -       pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = new ",
  -                       Double.class, "(", d, ");");
  -       pMethod.addEndIf();
  -    } else if (Column.Type.FLOAT.equals(type)) {
  -       LocalJavaField f = pMethod.newJavaField(float.class);
  -       f.addLine(pResultSet, ".getFloat(", p, ");");
  -       pMethod.addIf("!", pResultSet, ".wasNull()");
  -       pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = new ",
  -                       Float.class, "(", f, ");");
  -       pMethod.addEndIf();
  -    } else if (Column.Type.INTEGER.equals(type)) {
  -       LocalJavaField i = pMethod.newJavaField(int.class);
  -       i.addLine(pResultSet, ".getInt(", p, ");");
  -       pMethod.addIf("!", pResultSet, ".wasNull()");
  -       pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = new ",
  -                       Integer.class, "(", i, ");");
  -       pMethod.addEndIf();
  -    } else if (Column.Type.SMALLINT.equals(type)) {
  -       LocalJavaField s = pMethod.newJavaField(short.class);
  -       s.addLine(pResultSet, ".getShort(", p, ");");
  -       pMethod.addIf("!", pResultSet, ".wasNull()");
  -       pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = new ",
  -                       Short.class, "(", s, ");");
  -       pMethod.addEndIf();
  -    } else if (Column.Type.TIME.equals(type)) {
  -       pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = ",
  -                       pResultSet, ".getTime(", p, ");");
  -    } else if (Column.Type.TIMESTAMP.equals(type)) {
  -       pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = ",
  -                       pResultSet, ".getTimestamp(", p, ");");
  -    } else if (Column.Type.TINYINT.equals(type)) {
  -       LocalJavaField b = pMethod.newJavaField(short.class);
  -       b.addLine(pResultSet, ".getByte(", p, ");");
  -       pMethod.addIf("!", pResultSet, ".wasNull()");
  -       pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = new ",
  -                       Byte.class, "(", b, ");");
  -       pMethod.addEndIf();
  -    } else {
  -      throw new IllegalStateException("Unknown column type: " + type);
  -    }
  -  }
  -
  -  /** <p>Generates code for setting a PreparedStatement's parameter.</p>
  -   */
  -  protected void setPreparedStatementValue(JavaMethod pMethod, Column pColumn,
  -                                             Object pStmt, Object pParamNum,
  -                                             Object pValue) {
  -    if (!(pValue instanceof DirectAccessible)) {
  -       LocalJavaField v = pMethod.newJavaField(Object.class);
  -       v.addLine(pValue);
  -       pValue = v;
  -    }
  -
  -    Column.Type type = pColumn.getType();
  -    pMethod.addIf(pValue, " == null");
  -    pMethod.addLine(pStmt, ".setNull(", pParamNum, ", ", Types.class, ".",
  -                    type, ");");
  -    pMethod.addElse();
  -    if (Column.Type.BIGINT.equals(type)) {
  -      pMethod.addLine(pStmt, ".setLong(", pParamNum, ", ((", Long.class,
  -                      ") ", pValue, ").longValue());");
  -    } else if (pColumn.isBinaryColumn()) {
  -      pMethod.addLine(pStmt, ".setBytes(", pParamNum, ", (", byte[].class,
  -                      ") ", pValue, ");");
  -    } else if (Column.Type.BIT.equals(type)) {
  -      pMethod.addLine(pStmt, ".setBoolean(", pParamNum, ", ((", Boolean.class,
  -                      ") ", pValue, ").booleanValue());");
  -    } else if (pColumn.isStringColumn()) {
  -      pMethod.addLine(pStmt, ".setString(", pParamNum, ", (", String.class,
  -                      ") ", pValue, ");");
  -    } else if (Column.Type.DATE.equals(type)) {
  -      pMethod.addLine(pStmt, ".setDate(", pParamNum, ", (", Date.class,
  -                      ") ", pValue, ");");
  -    } else if (Column.Type.DOUBLE.equals(type)) {
  -      pMethod.addLine(pStmt, ".setDouble(", pParamNum, ", ((", Double.class,
  -                      ") ", pValue, ").doubleValue());");
  -    } else if (Column.Type.FLOAT.equals(type)) {
  -      pMethod.addLine(pStmt, ".setFloat(", pParamNum, ", ((", Float.class,
  -                      ") ", pValue, ").floatValue());");
  -    } else if (Column.Type.INTEGER.equals(type)) {
  -      pMethod.addLine(pStmt, ".setInt(", pParamNum, ", ((", Integer.class,
  -                      ") ", pValue, ").intValue());");
  -    } else if (Column.Type.SMALLINT.equals(type)) {
  -      pMethod.addLine(pStmt, ".setShort(", pParamNum, ", ((", Short.class,
  -                      ") ", pValue, ").shortValue());");
  -    } else if (Column.Type.TIME.equals(type)) {
  -      pMethod.addLine(pStmt, ".setTime(", pParamNum, ", (", Time.class,
  -                      ") ", pValue, ");");
  -    } else if (Column.Type.TIMESTAMP.equals(type)) {
  -      pMethod.addLine(pStmt, ".setTimestamp(", pParamNum, ", (", Timestamp.class,
  -                      ") ", pValue, ");");
  -    } else if (Column.Type.TINYINT.equals(type)) {
  -      pMethod.addLine(pStmt, ".setByte(", pParamNum, ", ((", Byte.class, ") ",
  -                      pValue, ").byteValue());");
  -    } else {
  -      throw new IllegalStateException("Unknown column type: " + type);
  -    }
  -
  -    pMethod.addEndIf();
  -  }
  -
  -  /** <p>Generates code for reading all rows matching the given key.</p>
  -   */
  -  protected void getSelectRowsCode(JavaMethod pMethod,
  -                                   TableInfo pTableInfo,
  -                                   ColumnSet pColumnSet,
  -                                   DirectAccessible pConn,
  -                                   DirectAccessible pMap,
  -                                   DirectAccessible pValues,
  -                                   boolean pReturnValue) {
  -    Table table = pTableInfo.getTable();
  -    SelectStatement statement = table.getSelectStatement();
  -    statement.getWhere().addColumnSetQuery(pColumnSet, statement.getTableReference());
  -    String s = table.getSchema().getSQLFactory().newSQLGenerator().getQuery(statement);
  -    Object query = JavaSource.getQuoted(s);
  -    if (isGeneratingLogging()) {
  -      LocalJavaField q = pMethod.newJavaField(String.class);
  -      q.addLine(query);
  -      query = q;
  -      logFinest(pMethod, query, pValues);
  -    }
  -
  -    LocalJavaField stmt = pMethod.newJavaField(PreparedStatement.class);
  -    stmt.addLine(pConn, ".prepareStatement(", JavaSource.getQuoted(s), ");");
  -    LocalJavaField isStmtClosed = pMethod.newJavaField(boolean.class);
  -    isStmtClosed.addLine("false");
  -    pMethod.addTry();
  -
  -    int paramNum = 0;
  -    for (Iterator iter = pColumnSet.getColumns();  iter.hasNext();  ) {
  -       Object v = new Object[]{pValues, "[", Integer.toString(paramNum), "]"};
  -       Column column = (Column) iter.next();
  -       setPreparedStatementValue(pMethod, column, stmt, Integer.toString(++paramNum), v);
  -    }
  -    LocalJavaField rs = pMethod.newJavaField(ResultSet.class, "rs");
  -    rs.addLine(stmt, ".executeQuery()");
  -    LocalJavaField isRsClosed = pMethod.newJavaField(boolean.class);
  -    isRsClosed.addLine("false");
  -    LocalJavaField result;
  -    if (pReturnValue) {
  -      result = pMethod.newJavaField(Object[].class, "result");
  -      result.addLine("null");
  -    } else {
  -      result = null;
  -    }
  -    pMethod.addTry();
  -
  -    pMethod.addWhile(rs, ".next()");
  -    if (result != null) {
  -      pMethod.addIf(result, " != null");
  -      pMethod.addThrowNew(IllegalStateException.class,
  -                          JavaSource.getQuoted("Expected a single row only."));
  -      pMethod.addEndIf();
  -    }
  -
  -    int resultColumnSize = 0;
  -    for (Iterator iter = table.getColumns();  iter.hasNext();  iter.next()) {
  -       ++resultColumnSize;
  -    }
  -    LocalJavaField row = pMethod.newJavaField(Object[].class, "row");
  -    row.addLine("new ", Object.class, "[" + resultColumnSize + "];");
  -
  -    int resultColumnNum = 0;
  -    for (Iterator iter = table.getColumns();  iter.hasNext();  ) {
  -       Column column = (Column) iter.next();
  -       setResultSetValue(pMethod, column, rs, resultColumnNum++, row);
  -    }
  -
  -    pMethod.addLine(((result == null) ? "" : "result = "),
  -                    getInsertRowMethodName(pTableInfo), "(", pConn, ", ", pMap, ", ",
  -                    row, ");");
  -     
  -    pMethod.addEndWhile();
  -    pMethod.addLine(isRsClosed, " = true;");
  -    pMethod.addLine(rs, ".close();");
  -
  -    pMethod.addFinally();
  -    pMethod.addIf("!", isRsClosed);
  -    pMethod.addTry();
  -    pMethod.addLine(rs, ".close();");
  -    pMethod.addCatch(Throwable.class, "pIgnore");
  -    pMethod.addEndTry();
  -    pMethod.addEndIf();
  -    pMethod.addEndTry();
  -
  -    pMethod.addLine(isStmtClosed, " = true;");
  -    pMethod.addLine(stmt, ".close();");
  -    if (result != null) {
  -      logExiting(pMethod, result);
  -      pMethod.addLine("return ", result, ";");
  -    } else {
  -      logFinestExiting(pMethod, null);
  -    }
  -
  -    pMethod.addFinally();
  -    pMethod.addIf("!", isStmtClosed);
  -    pMethod.addTry();
  -    pMethod.addLine(stmt, ".close();");
  -    pMethod.addCatch(Throwable.class, "pIgnore");
  -    pMethod.addEndTry();
  -    pMethod.addEndIf();
  -    pMethod.addEndTry();
  -    
  -  }
  -
  -  /** <p>Returns the name of the method for cloning one row from the
  -   * given table.</p>
  -   */
  -  protected String getInsertRowMethodName(TableInfo pTableInfo) {
  -     return "clone" + pTableInfo.getPropertyName() + "Row";
  -  }
  -
  -  /** <p>Creates an instance of the inner class CacheData by reading
  -   * the key from the given row.</p>
  -   */
  -  protected LocalJavaField getCacheDataClassInstance(JavaMethod pMethod,
  -                                                     TableInfo pTableInfo,
  -                                                     ColumnSet pColumnSet,
  -                                                     DirectAccessible pValues) {
  -    Table table = pColumnSet.getTable();
  -    List params = new ArrayList();
  -    for (Iterator iter = pColumnSet.getColumns();  iter.hasNext();  ) {
  -      Column primaryKeyColumn = (Column) iter.next();
  -      int index = -1;
  -      int i = 0;
  -      for (Iterator iter2 = table.getColumns();  iter2.hasNext();  ++i) {
  -        Column tableColumn = (Column) iter2.next();
  -        if (tableColumn.equals(primaryKeyColumn)) {
  -          index = i;
  -          break; 
  -        }
  -      }
  -      if (index == -1) {
  -        throw new IllegalStateException("Key column " + primaryKeyColumn.getQName() + " not found.");
  -      }
  -      if (params.size() > 0) {
  -        params.add(", ");
  -      }
  -      params.add(new Object[]{pValues, "[" + index + "]"});
  -    }
  -
  -    JavaQName cacheDataClass = getCacheDataClassName(pMethod.getJavaSource().getQName());
  -    LocalJavaField jf = pMethod.newJavaField(cacheDataClass);
  -    jf.addLine("new ", cacheDataClass, "(",
  -
  -    JavaSource.getQuoted(pTableInfo.getPropertyName()),
  -                         ", new ", Object[].class, "{", params, "})");
  -    return jf;
  -  }
  -
  -  /** <p>Updates a row by reading the values from an instance of the inner
  -   * class CacheData.</p>
  -   */
  -  protected void getApplyCacheData(JavaMethod pMethod,
  -                                   TableInfo pTableInfo,
  -                                   ColumnSet pColumnSet,
  -                                   DirectAccessible pRow,
  -                                   DirectAccessible pData) {
  -    Table table = pTableInfo.getTable();
  -    for (Iterator iter = pColumnSet.getColumns();  iter.hasNext();  ) {
  -      Column primaryKeyColumn = (Column) iter.next();
  -      int index = -1;
  -      int i = 0;
  -      for (Iterator iter2 = table.getColumns();  iter2.hasNext();  ++i) {
  -        Column tableColumn = (Column) iter2.next();
  -        if (tableColumn.equals(primaryKeyColumn)) {
  -          index = i;
  -          break; 
  -        }
  -      }
  -      if (index == -1) {
  -        throw new IllegalStateException("Key column " + primaryKeyColumn.getQName() + " not found.");
  -      }
  -      pMethod.addLine(pRow, "[" + index + "] = ", pData, "[" + (i+1) + "];");
  -    }
  -  }
  -
  -  /** <p>Creates a method for cloning one row from the given table.</p>
  -   */
  -  protected JavaMethod getInsertRowMethod(JavaSource pSource, TableInfo pTableInfo) {
  -    Table table = pTableInfo.getTable();
  -    JavaMethod jm = pSource.newJavaMethod(getInsertRowMethodName(pTableInfo),
  -                                          Object[].class, JavaSource.PRIVATE);
  -    jm.addThrows(SQLException.class);
  -    DirectAccessible connection = jm.addParam(Connection.class, "pConn");
  -    DirectAccessible map = jm.addParam(Map.class, "pMap");
  -    DirectAccessible values = jm.addParam(Object[].class, "pValue");
  -
  -    logFinestEntering(jm, values);
  -
  -    LocalJavaField baseKey = null;
  -    if (table.getPrimaryKey() != null) {
  -       baseKey = getCacheDataClassInstance(jm, pTableInfo,
  -                                                       table.getPrimaryKey(), values);
  -    jm.addIf(map, ".containsKey(", baseKey, ")");
  -    logFinestExiting(jm, JavaSource.getQuoted("null (Already cloned)"));
  -    jm.addLine("return null;");
  -    jm.addEndIf();
  -    }
  -
  -    for (Iterator iter = pTableInfo.getColumnUpdaters();  iter.hasNext();  ) {
  -       ((ColumnUpdater) iter.next()).update(jm, pTableInfo, connection, map, values);
  -    }
  -
  -    jm.addLine(jm.getName(), "(", connection, ", ", values, ");");
  -
  -    if (baseKey != null) {
  -    LocalJavaField clonedKey = getCacheDataClassInstance(jm, pTableInfo,
  -                                                         table.getPrimaryKey(),
  -                                                         values);
  -    jm.addLine(map, ".put(", baseKey, ", ", clonedKey, ");");
  -    }
  -
  -
  -    // Clone objects referencing this object
  -    LocalJavaField referencedValues = null;
  -    for (Iterator referencingIter = tablesByOrder.iterator();  referencingIter.hasNext();  ) {
  -      TableInfo prevTableInfo = (TableInfo) referencingIter.next();
  -      Table prevTable = prevTableInfo.getTable();
  -      for (Iterator fkIter = prevTable.getForeignKeys();  fkIter.hasNext();  ) {
  -        ForeignKey fk = (ForeignKey) fkIter.next();
  -        if (fk.getReferencedTable().equals(table)) {
  -          if (referencedValues == null) {
  -            referencedValues = jm.newJavaField(Object[].class);
  -            referencedValues.addLine(baseKey, ".getValues()");
  -          }
  -          getSelectRowsCode(jm, prevTableInfo, fk, connection, map, referencedValues, false);
  -        }
  -      }
  -    }
  -
  -    logFinestExiting(jm, values);
  -    jm.addLine("return ", values, ";");
  -
  -    return jm;
  -  }
  -
  -  /** <p>Creates a method for cloning one row from the given table.</p>
  -   */
  -  protected JavaMethod getInnerInsertRowMethod(JavaSource pSource, TableInfo pTableInfo) {
  -    Table table = pTableInfo.getTable();
  -    JavaMethod jm = pSource.newJavaMethod(getInsertRowMethodName(pTableInfo),
  -                                          JavaQNameImpl.VOID, JavaSource.PRIVATE);
  -    jm.addThrows(SQLException.class);
  -    DirectAccessible connection = jm.addParam(Connection.class, "pConn");
  -    DirectAccessible values = jm.addParam(Object[].class, "pValue");
  -
  -    logFinestEntering(jm, null);
  -
  -    InsertStatement insertStatement = table.getInsertStatement();
  -    String s = table.getSchema().getSQLFactory().newSQLGenerator().getQuery(insertStatement);
  -    Object query = JavaSource.getQuoted(s);
  -    if (isGeneratingLogging()) {
  -      LocalJavaField q = jm.newJavaField(String.class);
  -      q.addLine(query);
  -      query = q;
  -      logFinest(jm, query, values);
  -    }
  -    LocalJavaField stmt = jm.newJavaField(PreparedStatement.class, "stmt");
  -    stmt.setFinal(true);
  -    stmt.addLine(connection, ".prepareStatement(", JavaSource.getQuoted(s), ");");
  -    LocalJavaField isStmtClosed = jm.newJavaField(boolean.class, "isStmtClosed");
  -    isStmtClosed.addLine("false");
  -    jm.addTry();
  -
  -    int paramNum = 0;
  -    for (Iterator iter = table.getColumns();  iter.hasNext();  ) {
  -       Column column = (Column) iter.next();
  -       Object v = new Object[]{ values, "[", Integer.toString(paramNum), "]" };
  -       setPreparedStatementValue(jm, column, stmt, Integer.toString(++paramNum), v);
  -    }
  -
  -    jm.addLine(stmt, ".executeUpdate();");
  -    jm.addLine(isStmtClosed, " = true;");
  -    jm.addLine(stmt, ".close();");
  -
  -    jm.addFinally();
  -    jm.addIf("!", isStmtClosed);
  -    jm.addTry();
  -    jm.addLine(stmt, ".close();");
  -    jm.addCatch(Throwable.class, "ignore");
  -    jm.addEndTry();
  -    jm.addEndIf();
  -    jm.addEndTry();
  -
  -    logFinestExiting(jm, null);
  -    return jm;
  -  }
  -  
  -
  -  /** <p>Actually creates the public "clone" method.</p>
  -   */
  -  protected JavaMethod getPublicCloneMethod(JavaSource pSource) {
  -    TableInfo headTable;
  -    {
  -      Iterator iter = tablesByOrder.iterator();
  -      if (!iter.hasNext()) {
  -        throw new IllegalStateException("No tables have been added.");
  -      }
  -      headTable = (TableInfo) iter.next();
  -    }
  -   
  -    JavaQName resultType = JavaQNameImpl.getInstance(Object[].class);
  -    JavaMethod jm = pSource.newJavaMethod("clone", resultType, JavaSource.PUBLIC);
  -    jm.addThrows(SQLException.class);
  -    JavaComment jc = jm.newComment();
  -    jc.addLine("<p>This method takes as input the key values of a row in the table " +
  -               headTable.getTable().getQName() + ".");
  -    jc.addLine("The key values are given by the array <code>pRow</code>:");
  -    jc.addLine("<ul>");
  -    int i = 0;
  -    for (Iterator iter = headTable.getTable().getPrimaryKey().getColumns();
  -         iter.hasNext();  i++) {
  -      Column col = (Column) iter.next();
  -      jc.addLine("  <li><code>pRow[" + i+ "] = " + col.getQName() + "</code></li>");
  -    }
  -    jc.addLine("</ul>");
  -    jc.addLine("The method updates the rows version number and creates a new row");
  -    jc.addLine("with the updated values.</p>");
  -    {
  -      Iterator iter = tablesByOrder.iterator();
  -      iter.next();
  -      if (iter.hasNext()) {
  -        jc.addLine("<p>Once the new row is created, the method searches for entries");
  -        jc.addLine("referencing the old row in the following tables:");
  -        jc.addLine("<table>");
  -        do {
  -          TableInfo subTable = (TableInfo) iter.next();
  -          jc.addLine("  <tr><td>" + subTable.getTable().getQName() + "</td></tr>");
  -        } while (iter.hasNext());
  -        jc.addLine("All the referencing entries are cloned as well, with updated");
  -        jc.addLine("references.");
  -      }
  -    }
  -                 
  -    DirectAccessible conn = jm.addParam(Connection.class, "pConn");
  -    DirectAccessible row = jm.addParam(resultType, "pRow");
  -
  -    logEntering(jm, new Object[]{"new ", Object[].class, "{", conn, ", ", row, "}"});
  -
  -    LocalJavaField map = jm.newJavaField(Map.class, "clonedObjects");
  -    map.addLine("new ", HashMap.class, "()");
  -
  -    getSelectRowsCode(jm, headTable, headTable.getTable().getPrimaryKey(),
  -                      conn, map, row, true);
  -    return jm;
  -  }
  -
  -  /** <p>Creates a method for updating one row in the head table.</p>
  -   */
  -  public JavaMethod getCloneMethod(JavaSource pSource) {
  -     initLogging(pSource);
  -
  -     for (Iterator iter = tablesByOrder.iterator();  iter.hasNext();  ) {
  -        TableInfo tableInfo = (TableInfo) iter.next();
  -
  -        getInsertRowMethod(pSource, tableInfo);
  -        getInnerInsertRowMethod(pSource, tableInfo);
  -     }
  -     getCacheDataClass(pSource);
  -     getPublicCloneMethod(pSource);
  -
  -     return null;
  -  }
  +	/** <p>The ColumnUpdater is able to update one or more columns in a
  +	 * table. Such a column update is required, because the cloned tables
  +	 * must not have the same primary key.</p>
  +	 * <p>The typical use is to specify a ColumnUpdater for the head
  +	 * table, which bumps the version number. For any child table
  +	 * you could specify a ColumnUpdater which generates a new primary
  +	 * key.</p>
  +	 */
  +	public interface ColumnUpdater {
  +		/** <p>Generates code for updating a table row. The row is supplied
  +		 * as an array of objects. The order of objects matches the columns
  +		 * of the given table.</p>
  +		 * @param pMethod The method being created; may be used to generate
  +		 *   local fields, etc.
  +		 * @param pTableInfo The table being updated
  +		 * @param pMap A local Java field with a Map of rows, that have already
  +		 *   been cloned. The keys and values are both instances of the generated
  +		 *   inner class DataCache. The keys are holding the primary keys of
  +		 *   the original rows (which have been cloned) and the values are the
  +		 *   primary keys of the created rows (the generated clones).
  +		 * @param pConnection A local Java field with an open database connection
  +		 * @param pRow A local Java field with an array of values being cloned
  +		 */
  +		public void update(JavaMethod pMethod, TableInfo pTableInfo,
  +						   DirectAccessible pConnection,
  +						   DirectAccessible pMap,
  +						   DirectAccessible pRow);
  +	}
  +	
  +	/** <p>This class is used internally to maintain the informations on
  +	 * the tables being cloned.</p>
  +	 */
  +	public static class TableInfo {
  +		private final Table table;
  +		private final String propertyName;
  +		private boolean isReferenced;
  +		private boolean hasPrimaryKey;
  +		private final List columnUpdaters = new ArrayList();
  +		TableInfo(Table pTable, String pPropertyName) {
  +			table = pTable;
  +			propertyName = pPropertyName;
  +		}
  +		public Table getTable() { return table; }
  +		public String getPropertyName() { return propertyName; }
  +		public void add(ColumnUpdater pColumnUpdater) {
  +			columnUpdaters.add(pColumnUpdater);
  +		}
  +		public Iterator getColumnUpdaters() { return columnUpdaters.iterator(); }
  +		
  +		public void setReferenced(boolean pReferenced) {
  +			isReferenced = true;
  +		}
  +		public boolean isReferenced() {
  +			return isReferenced;
  +		}
  +		public boolean hasPrimaryKey() {
  +			return hasPrimaryKey;
  +		}
  +		public void setPrimaryKey(boolean pPrimaryKey) {
  +			hasPrimaryKey  = pPrimaryKey;
  +		}
  +	}
  +	
  +	/** <p>An implementation of {@link ColumnUpdater}, which updates foreign
  +	 * key references.</p>
  +	 */
  +	private class ForeignKeyUpdater implements ColumnUpdater {
  +		private final ForeignKey foreignKey;
  +		private final TableInfo referencedTable;
  +		
  +		private ForeignKeyUpdater(ForeignKey pForeignKey, TableInfo pReferencedTable) {
  +			foreignKey = pForeignKey;
  +			referencedTable = pReferencedTable;
  +		}
  +		
  +		public void update(JavaMethod pMethod, TableInfo pTableInfo,
  +						   DirectAccessible pConnection,
  +						   DirectAccessible pMap, DirectAccessible pRow) {
  +			LocalJavaField referencedKey = getCacheDataClassInstance(pMethod,
  +					referencedTable,
  +					foreignKey, pRow);
  +			LocalJavaField mappedKey = pMethod.newJavaField(referencedKey.getType());
  +			mappedKey.addLine("(", referencedKey.getType(), ") ", pMap, ".get(",
  +					referencedKey, ")");
  +			pMethod.addIf(mappedKey, " == null");
  +			pMethod.addThrowNew(IllegalStateException.class,
  +					JavaSource.getQuoted("Unknown reference: "), " + ",
  +					referencedKey);
  +			pMethod.addEndIf();
  +			int valNum = 0;
  +			for (Iterator iter = referencedTable.getTable().getPrimaryKey().getColumns();  iter.hasNext();  ) {
  +				Column referencedKeyColumn = (Column) iter.next();
  +				Column localColumn = null;
  +				for (Iterator iter2 = foreignKey.getColumnLinks();  iter2.hasNext();  ) {
  +					ForeignKey.ColumnLink link = (ForeignKey.ColumnLink) iter2.next();
  +					if (link.getReferencedColumn().equals(referencedKeyColumn)) {
  +						localColumn = link.getLocalColumn();
  +						break;
  +					}
  +				}
  +				if (localColumn == null) {
  +					throw new IllegalStateException("Unable to find the column referencing " + referencedKeyColumn.getQName());
  +				}
  +				
  +				int colNum = -1, i = 0;
  +				for (Iterator iter2 = pTableInfo.getTable().getColumns();  iter2.hasNext();  ) {
  +					Column col = (Column) iter2.next();
  +					if (col.equals(localColumn)) {
  +						colNum = i;
  +						break;
  +					}
  +					++i;
  +				}
  +				if (colNum == -1) {
  +					throw new IllegalStateException("Unable to find the column " + localColumn.getQName() + " in table " + pTableInfo.getTable().getQName());
  +				}
  +				pMethod.addLine(pRow, "[" + colNum + "] = ", mappedKey, ".getValues()[" + valNum++ + "];");
  +			}
  +		}
  +	}
  +	
  +	private List tablesByOrder = new ArrayList();
  +	private Map tablesByName = new HashMap();
  +	private Set propertyNames = new HashSet();
  +	private boolean generatingLogging;
  +	
  +	private boolean isReferencing(Table pReferencingTable, Table pReferencedTable) {
  +		for (Iterator iter = pReferencingTable.getForeignKeys();  iter.hasNext();  ) {
  +			ForeignKey foreignKey = (ForeignKey) iter.next();
  +			if (foreignKey.getReferencedTable().equals(pReferencedTable)) {
  +				return true;
  +			}
  +		}
  +		return false;
  +	}
  +	
  +	/** <p>Returns whether the generator is creating logging statements. By default
  +	 * no logging statements are created.</p>
  +	 * <p>The default
  +	 * implementation creates logging statements suitable for the JaxMe logging
  +	 * package. To change this, create a subclass and overwrite the following
  +	 * methods: {@link #logEntering(JavaMethod, Object)},
  +	 * {@link #logExiting(JavaMethod, Object)}, {@link #logFinest(JavaMethod, Object, Object)},
  +	 * {@link #logFinestEntering(JavaMethod, Object)}, and
  +	 * {@link #logFinestExiting(JavaMethod, Object)}.</p>
  +	 * @see #setGeneratingLogging(boolean)
  +	 */
  +	public boolean isGeneratingLogging() {
  +		return generatingLogging;
  +	}
  +	
  +	/** <p>Sets whether the generator is creating logging statements. By default
  +	 * no logging statements are created.</p>
  +	 * <p>The default
  +	 * implementation creates logging statements suitable for the JaxMe logging
  +	 * package. To change this, create a subclass and overwrite the following
  +	 * methods: {@link #logEntering(JavaMethod, Object)},
  +	 * {@link #logExiting(JavaMethod, Object)}, {@link #logFinest(JavaMethod, Object, Object)},
  +	 * {@link #logFinestEntering(JavaMethod, Object)}, and
  +	 * {@link #logFinestExiting(JavaMethod, Object)}.</p>
  +	 * @see #isGeneratingLogging()
  +	 */
  +	public void setGeneratingLogging(boolean pGeneratingLogging) {
  +		generatingLogging = pGeneratingLogging;
  +	}
  +	
  +	/** <p>Creates the code for initialization of the logging framework.
  +	 * The default implementation generates code creating an instance of
  +	 * {@link org.apache.ws.jaxme.logging.Logger}.</p>
  +	 */
  +	protected void initLogging(JavaSource pSource) {
  +		if (isGeneratingLogging()) {
  +			JavaField jf = pSource.newJavaField("logger", Logger.class, JavaSource.PRIVATE);
  +			jf.setFinal(true);
  +			jf.setStatic(true);
  +			jf.addLine(LoggerAccess.class, ".getLogger(", pSource.getQName(), ".class)");
  +		}
  +	}
  +	
  +	/** <p>Creates code for logging the entrance into a method with
  +	 * fine level.</p>
  +	 * <p><em>Note:</em> The method should consider the {@link #isGeneratingLogging()}
  +	 * value.</p>
  +	 *
  +	 * @param pMethod The method in which a logging statement should be inserted
  +	 * @param pValues An array of additional values, possibly null
  +	 */
  +	protected void logEntering(JavaMethod pMethod, Object pValues) {
  +		if (isGeneratingLogging()) {
  +			LocalJavaField mName = pMethod.newJavaField(String.class, "mName");
  +			mName.addLine(JavaSource.getQuoted(pMethod.getLoggingSignature()));
  +			mName.setFinal(true);
  +			if (pValues == null) {
  +				pMethod.addLine("logger.entering(", mName, ");");
  +			} else {
  +				pMethod.addLine("logger.entering(", mName, ", ", pValues, ");");         
  +			}
  +		}
  +	}
  +	
  +	/** <p>Creates code for logging the entrance into a method with
  +	 * finest level.</p>
  +	 * <p><em>Note:</em> The method should consider the {@link #isGeneratingLogging()}
  +	 * value.</p>
  +	 * <p><em>Implementation note:</em> The default implementation is
  +	 * equivalent to <code>logFinest(pMethod, "->", pValues)</code>.</p>
  +	 *
  +	 * @param pMethod The method in which a logging statement should be inserted
  +	 * @param pValues An array of additional values, possibly null
  +	 */
  +	protected void logFinestEntering(JavaMethod pMethod, Object pValues) {
  +		if (isGeneratingLogging()) {
  +			LocalJavaField mName = pMethod.newJavaField(String.class, "mName");
  +			mName.addLine(JavaSource.getQuoted(pMethod.getLoggingSignature()));
  +			mName.setFinal(true);
  +			logFinest(pMethod, JavaSource.getQuoted("->"), pValues);
  +		}
  +	}
  +	
  +	/** <p>Creates code for logging the exit from a method with
  +	 * fine level.</p>
  +	 * <p><em>Note:</em> The method should consider the {@link #isGeneratingLogging()}
  +	 * value.</p>
  +	 *
  +	 * @param pMethod The method in which a logging statement should be inserted
  +	 * @param pValues An array of additional values, possibly null
  +	 */
  +	protected void logExiting(JavaMethod pMethod, Object pValues) {
  +		if (isGeneratingLogging()) {
  +			if (pValues == null) {
  +				pMethod.addLine("logger.exiting(mName);");
  +			} else {
  +				pMethod.addLine("logger.exiting(mName, ", pValues, ");");        
  +			}
  +		}
  +	}
  +	
  +	/** <p>Creates code for logging the exit from a method with
  +	 * fine level.</p>
  +	 * <p><em>Note:</em> The method should consider the {@link #isGeneratingLogging()}
  +	 * value.</p>
  +	 * <p><em>Implementation note:</em> The default implementation is
  +	 * equivalent to <code>logFinest(pMethod, "<-", pValues)</code>.</p>
  +	 *
  +	 * @param pMethod The method in which a logging statement should be inserted
  +	 * @param pValues An array of additional values, possibly null
  +	 */
  +	protected void logFinestExiting(JavaMethod pMethod, Object pValues) {
  +		logFinest(pMethod, JavaSource.getQuoted("->"), pValues);
  +	}
  +	
  +	/** <p>Creates code for logging a message with finest level.</p>
  +	 * <p><em>Note:</em> The method should consider the {@link #isGeneratingLogging()}
  +	 * value.</p>
  +	 *
  +	 * @param pMethod The method in which a logging statement should be inserted
  +	 * @param pMsg The message being logged
  +	 * @param pValues An array of additional values, possibly null
  +	 */
  +	protected void logFinest(JavaMethod pMethod, Object pMsg, Object pValues) {
  +		if (isGeneratingLogging()) {
  +			if (pValues == null) {
  +				pMethod.addLine("logger.finest(mName, ", pMsg, ");");
  +			} else {
  +				pMethod.addLine("logger.finest(mName, ", pMsg, ", ", pValues, ");");
  +			}
  +		}
  +	}
  +	
  +	/** Adds a new table to the list of tables. The table must not
  +	 * contain a forward reference. Additionally, the table must not
  +	 * be referenced by any other table, which has already been added
  +	 * to the list.</p>
  +	 * @param pTable The table being cloned
  +	 * @param pUpdater The column updater to use for changing the
  +	 *   updated columns.
  +	 */
  +	public void addTable(Table pTable, ColumnUpdater pUpdater) {
  +		String name = pTable.getQName();
  +		if (tablesByName.containsKey(pTable)) {
  +			throw new IllegalStateException("A table " + name + " has already been added.");
  +		}
  +		if (isReferencing(pTable, pTable)) {
  +			throw new IllegalStateException("The table " + name + " is containing self references.");
  +		}
  +		for (Iterator iter = tablesByOrder.iterator();  iter.hasNext();  ) {
  +			TableInfo tableInfo = (TableInfo) iter.next();
  +			if (isReferencing(tableInfo.getTable(), pTable)) {
  +				throw new IllegalStateException("The table " + tableInfo.getTable().getQName() +
  +						" contains a forward reference to the table " + name + ".");
  +			}
  +		}
  +		
  +		String s = pTable.getName().getName();
  +		String t = s;
  +		int num = 0;
  +		for (;;) {
  +			t = Character.toUpperCase(t.charAt(0)) + t.substring(1);
  +			if (!propertyNames.contains(t)) {
  +				break;
  +			}
  +			t = s + num++;
  +		}
  +		propertyNames.add(t);
  +		
  +		TableInfo tableInfo = new TableInfo(pTable, t);
  +		tableInfo.setPrimaryKey(pTable.getPrimaryKey() != null);
  +		if (pUpdater != null) {
  +			tableInfo.add(pUpdater);
  +		}
  +		
  +		for (Iterator iter = pTable.getForeignKeys();  iter.hasNext();  ) {
  +			ForeignKey foreignKey = (ForeignKey) iter.next();
  +			Table referencedTable = foreignKey.getReferencedTable();
  +			for (Iterator iter2 = tablesByOrder.iterator();  iter2.hasNext();  ) {
  +				TableInfo referencedTableInfo = (TableInfo) iter2.next();
  +				if (referencedTableInfo.getTable().equals(referencedTable)) {
  +					ColumnUpdater columnUpdater = new ForeignKeyUpdater(foreignKey, referencedTableInfo);
  +					tableInfo.add(columnUpdater);
  +					if (!referencedTableInfo.hasPrimaryKey()) {
  +						throw new IllegalStateException("The table " + pTable.getQName() +
  +								" is referencing table " + referencedTable.getQName() +
  +						", which doesn't have a primary key.");
  +					}
  +					referencedTableInfo.setReferenced(true);
  +				}
  +			}
  +		}
  +		
  +		tablesByName.put(name, tableInfo);
  +		tablesByOrder.add(tableInfo);
  +	}
  +	
  +	/** <p>Returns the name of the inner class CacheData.</p>
  +	 */
  +	protected JavaQName getCacheDataClassName(JavaQName pQName) {
  +		return JavaQNameImpl.getInnerInstance(pQName, "CacheData");
  +	}
  +	
  +	/** <p>Generates the innner class CacheData.</p>
  +	 */
  +	protected JavaInnerClass getCacheDataClass(JavaSource pSource) {
  +		JavaInnerClass jic = pSource.newJavaInnerClass("CacheData", JavaSource.PRIVATE);
  +		
  +		JavaField name = jic.newJavaField("name", String.class, JavaSource.PRIVATE);
  +		name.setFinal(true);
  +		JavaField values = jic.newJavaField("values", Object[].class, JavaSource.PRIVATE);
  +		values.setFinal(true);
  +		
  +		JavaConstructor jcon = jic.newJavaConstructor(JavaSource.PRIVATE);
  +		DirectAccessible pName = jcon.addParam(String.class, "pName");
  +		DirectAccessible pValues = jcon.addParam(Object[].class, "pValues");
  +		jcon.addLine(name, " = ", pName, ";");
  +		jcon.addLine(values, " = ", pValues, ";");
  +		
  +		JavaMethod getNameMethod = jic.newJavaMethod("getName", String.class, JavaSource.PUBLIC);
  +		getNameMethod.addLine("return ", name, ";");
  +		
  +		JavaMethod getValuesMethod = jic.newJavaMethod("getValues", Object[].class, JavaSource.PUBLIC);
  +		getValuesMethod.addLine("return ", values, ";");
  +		
  +		{
  +			JavaMethod jm = jic.newJavaMethod("toString", String.class, JavaSource.PUBLIC);
  +			LocalJavaField sb = jm.newJavaField(StringBuffer.class, "sb");
  +			sb.addLine("new ", StringBuffer.class, "(", name, ")");
  +			DirectAccessible loopVar = jm.addForArray(values);
  +			jm.addLine(sb, ".append(", JavaSource.getQuoted(", "), ").append(",
  +					values, "[", loopVar, "]);");
  +			jm.addEndFor();
  +			jm.addLine("return ", sb, ".toString();");
  +			
  +		}
  +		
  +		{
  +			JavaMethod jm = jic.newJavaMethod("hashCode", int.class, JavaSource.PUBLIC);
  +			LocalJavaField hashCodeResult = jm.newJavaField(int.class, "result");
  +			hashCodeResult.addLine(name, ".hashCode() + ", values, ".length;");
  +			DirectAccessible loopVar = jm.addForArray(values);
  +			LocalJavaField o = jm.newJavaField(Object.class, "o");
  +			o.addLine(values, "[", loopVar, "]");
  +			jm.addIf(o, " != null");
  +			jm.addLine(hashCodeResult, " += ", o, ".hashCode();");
  +			jm.addEndIf();
  +			jm.addEndFor();
  +			jm.addLine("return ", hashCodeResult, ";");
  +		}
  +		
  +		{
  +			JavaMethod jm = jic.newJavaMethod("equals", boolean.class, JavaSource.PUBLIC);
  +			DirectAccessible o = jm.addParam(Object.class, "o");
  +			jm.addIf(o, " == null  ||  !(", o, " instanceof ", jic.getQName(), ")");
  +			jm.addLine("return false;");
  +			jm.addEndIf();
  +			LocalJavaField other = jm.newJavaField(jic.getQName(), "other");
  +			other.addLine("(", jic.getQName(), ") ", o);
  +			jm.addIf("!", name, ".equals(", other, ".name)  ||  ", values, ".length != ",
  +					other, ".values.length");
  +			jm.addLine("return false;");
  +			jm.addEndIf();
  +			DirectAccessible loopVar = jm.addForArray(values);
  +			LocalJavaField v = jm.newJavaField(Object.class, "v");
  +			v.addLine(values, "[", loopVar, "]");
  +			jm.addIf(v, " == null");
  +			jm.addIf(other, ".values[", loopVar, "] != null");
  +			jm.addLine("return false;");
  +			jm.addEndIf();
  +			jm.addElse();
  +			jm.addIf("!", v, ".equals(", other, ".values[", loopVar, "])");
  +			jm.addLine("return false;");
  +			jm.addEndIf();
  +			jm.addEndIf();
  +			jm.addEndFor();
  +			jm.addLine("return true;");
  +		}
  +		
  +		return jic;
  +	}
  +	
  +	/** <p>Generates code for reading a ResultSet's column.</p>
  +	 */
  +	protected void setResultSetValue(JavaMethod pMethod, Column pColumn,
  +									 DirectAccessible pResultSet,
  +									 int pColumnNum, Object pTarget) {
  +		Integer p = new Integer(pColumnNum+1);
  +		
  +		Column.Type type = pColumn.getType();
  +		if (Column.Type.BIGINT.equals(type)) {
  +			LocalJavaField l = pMethod.newJavaField(long.class);
  +			l.addLine(pResultSet, ".getLong(", p, ");");
  +			pMethod.addIf("!", pResultSet, ".wasNull()");
  +			pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = new ",
  +					Long.class, "(", l, ");");
  +			pMethod.addEndIf();
  +		} else if (pColumn.isBinaryColumn()) {
  +			pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = ",
  +					pResultSet, ".getBytes(", p, ");");
  +		} else if (Column.Type.BIT.equals(type)) {
  +			LocalJavaField b = pMethod.newJavaField(boolean.class);
  +			b.addLine(pResultSet, ".getBoolean(", p, ");");
  +			pMethod.addIf("!", pResultSet, ".wasNull()");
  +			pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = ", b,
  +					" ? ", Boolean.class, ".TRUE : ", Boolean.class, ".FALSE;");
  +			pMethod.addEndIf();
  +		} else if (pColumn.isStringColumn()) {
  +			pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = ",
  +					pResultSet, ".getString(", p, ");");
  +		} else if (Column.Type.DATE.equals(type)) {
  +			pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = ",
  +					pResultSet, ".getDate(", p, ");");
  +		} else if (Column.Type.DOUBLE.equals(type)) {
  +			LocalJavaField d = pMethod.newJavaField(double.class);
  +			d.addLine(pResultSet, ".getDouble(", p, ");");
  +			pMethod.addIf("!", pResultSet, ".wasNull()");
  +			pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = new ",
  +					Double.class, "(", d, ");");
  +			pMethod.addEndIf();
  +		} else if (Column.Type.FLOAT.equals(type)) {
  +			LocalJavaField f = pMethod.newJavaField(float.class);
  +			f.addLine(pResultSet, ".getFloat(", p, ");");
  +			pMethod.addIf("!", pResultSet, ".wasNull()");
  +			pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = new ",
  +					Float.class, "(", f, ");");
  +			pMethod.addEndIf();
  +		} else if (Column.Type.INTEGER.equals(type)) {
  +			LocalJavaField i = pMethod.newJavaField(int.class);
  +			i.addLine(pResultSet, ".getInt(", p, ");");
  +			pMethod.addIf("!", pResultSet, ".wasNull()");
  +			pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = new ",
  +					Integer.class, "(", i, ");");
  +			pMethod.addEndIf();
  +		} else if (Column.Type.SMALLINT.equals(type)) {
  +			LocalJavaField s = pMethod.newJavaField(short.class);
  +			s.addLine(pResultSet, ".getShort(", p, ");");
  +			pMethod.addIf("!", pResultSet, ".wasNull()");
  +			pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = new ",
  +					Short.class, "(", s, ");");
  +			pMethod.addEndIf();
  +		} else if (Column.Type.TIME.equals(type)) {
  +			pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = ",
  +					pResultSet, ".getTime(", p, ");");
  +		} else if (Column.Type.TIMESTAMP.equals(type)) {
  +			pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = ",
  +					pResultSet, ".getTimestamp(", p, ");");
  +		} else if (Column.Type.TINYINT.equals(type)) {
  +			LocalJavaField b = pMethod.newJavaField(short.class);
  +			b.addLine(pResultSet, ".getByte(", p, ");");
  +			pMethod.addIf("!", pResultSet, ".wasNull()");
  +			pMethod.addLine(pTarget, "[", Integer.toString(pColumnNum), "] = new ",
  +					Byte.class, "(", b, ");");
  +			pMethod.addEndIf();
  +		} else {
  +			throw new IllegalStateException("Unknown column type: " + type);
  +		}
  +	}
  +	
  +	/** <p>Generates code for setting a PreparedStatement's parameter.</p>
  +	 */
  +	protected void setPreparedStatementValue(JavaMethod pMethod, Column pColumn,
  +											 Object pStmt, Object pParamNum,
  +											 Object pValue) {
  +		if (!(pValue instanceof DirectAccessible)) {
  +			LocalJavaField v = pMethod.newJavaField(Object.class);
  +			v.addLine(pValue);
  +			pValue = v;
  +		}
  +		
  +		Column.Type type = pColumn.getType();
  +		pMethod.addIf(pValue, " == null");
  +		pMethod.addLine(pStmt, ".setNull(", pParamNum, ", ", Types.class, ".",
  +				type, ");");
  +		pMethod.addElse();
  +		if (Column.Type.BIGINT.equals(type)) {
  +			pMethod.addLine(pStmt, ".setLong(", pParamNum, ", ((", Long.class,
  +					") ", pValue, ").longValue());");
  +		} else if (pColumn.isBinaryColumn()) {
  +			pMethod.addLine(pStmt, ".setBytes(", pParamNum, ", (", byte[].class,
  +					") ", pValue, ");");
  +		} else if (Column.Type.BIT.equals(type)) {
  +			pMethod.addLine(pStmt, ".setBoolean(", pParamNum, ", ((", Boolean.class,
  +					") ", pValue, ").booleanValue());");
  +		} else if (pColumn.isStringColumn()) {
  +			pMethod.addLine(pStmt, ".setString(", pParamNum, ", (", String.class,
  +					") ", pValue, ");");
  +		} else if (Column.Type.DATE.equals(type)) {
  +			pMethod.addLine(pStmt, ".setDate(", pParamNum, ", (", Date.class,
  +					") ", pValue, ");");
  +		} else if (Column.Type.DOUBLE.equals(type)) {
  +			pMethod.addLine(pStmt, ".setDouble(", pParamNum, ", ((", Double.class,
  +					") ", pValue, ").doubleValue());");
  +		} else if (Column.Type.FLOAT.equals(type)) {
  +			pMethod.addLine(pStmt, ".setFloat(", pParamNum, ", ((", Float.class,
  +					") ", pValue, ").floatValue());");
  +		} else if (Column.Type.INTEGER.equals(type)) {
  +			pMethod.addLine(pStmt, ".setInt(", pParamNum, ", ((", Integer.class,
  +					") ", pValue, ").intValue());");
  +		} else if (Column.Type.SMALLINT.equals(type)) {
  +			pMethod.addLine(pStmt, ".setShort(", pParamNum, ", ((", Short.class,
  +					") ", pValue, ").shortValue());");
  +		} else if (Column.Type.TIME.equals(type)) {
  +			pMethod.addLine(pStmt, ".setTime(", pParamNum, ", (", Time.class,
  +					") ", pValue, ");");
  +		} else if (Column.Type.TIMESTAMP.equals(type)) {
  +			pMethod.addLine(pStmt, ".setTimestamp(", pParamNum, ", (", Timestamp.class,
  +					") ", pValue, ");");
  +		} else if (Column.Type.TINYINT.equals(type)) {
  +			pMethod.addLine(pStmt, ".setByte(", pParamNum, ", ((", Byte.class, ") ",
  +					pValue, ").byteValue());");
  +		} else {
  +			throw new IllegalStateException("Unknown column type: " + type);
  +		}
  +		
  +		pMethod.addEndIf();
  +	}
  +	
  +	/** <p>Generates code for reading all rows matching the given key.</p>
  +	 */
  +	protected void getSelectRowsCode(JavaMethod pMethod,
  +									 TableInfo pTableInfo,
  +									 ColumnSet pColumnSet,
  +									 DirectAccessible pConn,
  +									 DirectAccessible pMap,
  +									 DirectAccessible pValues,
  +									 boolean pReturnValue) {
  +		Table table = pTableInfo.getTable();
  +		SelectStatement statement = table.getSelectStatement();
  +		statement.getWhere().addColumnSetQuery(pColumnSet, statement.getTableReference());
  +		String s = table.getSchema().getSQLFactory().newSQLGenerator().getQuery(statement);
  +		Object query = JavaSource.getQuoted(s);
  +		if (isGeneratingLogging()) {
  +			LocalJavaField q = pMethod.newJavaField(String.class);
  +			q.addLine(query);
  +			query = q;
  +			logFinest(pMethod, query, pValues);
  +		}
  +		
  +		LocalJavaField stmt = pMethod.newJavaField(PreparedStatement.class);
  +		stmt.addLine(pConn, ".prepareStatement(", JavaSource.getQuoted(s), ");");
  +		LocalJavaField isStmtClosed = pMethod.newJavaField(boolean.class);
  +		isStmtClosed.addLine("false");
  +		pMethod.addTry();
  +		
  +		int paramNum = 0;
  +		for (Iterator iter = pColumnSet.getColumns();  iter.hasNext();  ) {
  +			Object v = new Object[]{pValues, "[", Integer.toString(paramNum), "]"};
  +			Column column = (Column) iter.next();
  +			setPreparedStatementValue(pMethod, column, stmt, Integer.toString(++paramNum), v);
  +		}
  +		LocalJavaField rs = pMethod.newJavaField(ResultSet.class, "rs");
  +		rs.addLine(stmt, ".executeQuery()");
  +		LocalJavaField isRsClosed = pMethod.newJavaField(boolean.class);
  +		isRsClosed.addLine("false");
  +		LocalJavaField result;
  +		if (pReturnValue) {
  +			result = pMethod.newJavaField(Object[].class, "result");
  +			result.addLine("null");
  +		} else {
  +			result = null;
  +		}
  +		pMethod.addTry();
  +		
  +		pMethod.addWhile(rs, ".next()");
  +		if (result != null) {
  +			pMethod.addIf(result, " != null");
  +			pMethod.addThrowNew(IllegalStateException.class,
  +					JavaSource.getQuoted("Expected a single row only."));
  +			pMethod.addEndIf();
  +		}
  +		
  +		int resultColumnSize = 0;
  +		for (Iterator iter = table.getColumns();  iter.hasNext();  iter.next()) {
  +			++resultColumnSize;
  +		}
  +		LocalJavaField row = pMethod.newJavaField(Object[].class, "row");
  +		row.addLine("new ", Object.class, "[" + resultColumnSize + "];");
  +		
  +		int resultColumnNum = 0;
  +		for (Iterator iter = table.getColumns();  iter.hasNext();  ) {
  +			Column column = (Column) iter.next();
  +			setResultSetValue(pMethod, column, rs, resultColumnNum++, row);
  +		}
  +		
  +		pMethod.addLine(((result == null) ? "" : "result = "),
  +				getInsertRowMethodName(pTableInfo), "(", pConn, ", ", pMap, ", ",
  +				row, ");");
  +		
  +		pMethod.addEndWhile();
  +		pMethod.addLine(isRsClosed, " = true;");
  +		pMethod.addLine(rs, ".close();");
  +		
  +		pMethod.addFinally();
  +		pMethod.addIf("!", isRsClosed);
  +		pMethod.addTry();
  +		pMethod.addLine(rs, ".close();");
  +		pMethod.addCatch(Throwable.class, "pIgnore");
  +		pMethod.addEndTry();
  +		pMethod.addEndIf();
  +		pMethod.addEndTry();
  +		
  +		pMethod.addLine(isStmtClosed, " = true;");
  +		pMethod.addLine(stmt, ".close();");
  +		if (result != null) {
  +			logExiting(pMethod, result);
  +			pMethod.addLine("return ", result, ";");
  +		} else {
  +			logFinestExiting(pMethod, null);
  +		}
  +		
  +		pMethod.addFinally();
  +		pMethod.addIf("!", isStmtClosed);
  +		pMethod.addTry();
  +		pMethod.addLine(stmt, ".close();");
  +		pMethod.addCatch(Throwable.class, "pIgnore");
  +		pMethod.addEndTry();
  +		pMethod.addEndIf();
  +		pMethod.addEndTry();
  +		
  +	}
  +	
  +	/** <p>Returns the name of the method for cloning one row from the
  +	 * given table.</p>
  +	 */
  +	protected String getInsertRowMethodName(TableInfo pTableInfo) {
  +		return "clone" + pTableInfo.getPropertyName() + "Row";
  +	}
  +	
  +	/** <p>Creates an instance of the inner class CacheData by reading
  +	 * the key from the given row.</p>
  +	 */
  +	protected LocalJavaField getCacheDataClassInstance(JavaMethod pMethod,
  +													   TableInfo pTableInfo,
  +													   ColumnSet pColumnSet,
  +													   DirectAccessible pValues) {
  +		Table table = pColumnSet.getTable();
  +		List params = new ArrayList();
  +		for (Iterator iter = pColumnSet.getColumns();  iter.hasNext();  ) {
  +			Column primaryKeyColumn = (Column) iter.next();
  +			int index = -1;
  +			int i = 0;
  +			for (Iterator iter2 = table.getColumns();  iter2.hasNext();  ++i) {
  +				Column tableColumn = (Column) iter2.next();
  +				if (tableColumn.equals(primaryKeyColumn)) {
  +					index = i;
  +					break; 
  +				}
  +			}
  +			if (index == -1) {
  +				throw new IllegalStateException("Key column " + primaryKeyColumn.getQName() + " not found.");
  +			}
  +			if (params.size() > 0) {
  +				params.add(", ");
  +			}
  +			params.add(new Object[]{pValues, "[" + index + "]"});
  +		}
  +		
  +		JavaQName cacheDataClass = getCacheDataClassName(pMethod.getJavaSource().getQName());
  +		LocalJavaField jf = pMethod.newJavaField(cacheDataClass);
  +		jf.addLine("new ", cacheDataClass, "(",
  +				
  +				JavaSource.getQuoted(pTableInfo.getPropertyName()),
  +				", new ", Object[].class, "{", params, "})");
  +		return jf;
  +	}
  +	
  +	/** <p>Updates a row by reading the values from an instance of the inner
  +	 * class CacheData.</p>
  +	 */
  +	protected void getApplyCacheData(JavaMethod pMethod,
  +									 TableInfo pTableInfo,
  +									 ColumnSet pColumnSet,
  +									 DirectAccessible pRow,
  +									 DirectAccessible pData) {
  +		Table table = pTableInfo.getTable();
  +		for (Iterator iter = pColumnSet.getColumns();  iter.hasNext();  ) {
  +			Column primaryKeyColumn = (Column) iter.next();
  +			int index = -1;
  +			int i = 0;
  +			for (Iterator iter2 = table.getColumns();  iter2.hasNext();  ++i) {
  +				Column tableColumn = (Column) iter2.next();
  +				if (tableColumn.equals(primaryKeyColumn)) {
  +					index = i;
  +					break; 
  +				}
  +			}
  +			if (index == -1) {
  +				throw new IllegalStateException("Key column " + primaryKeyColumn.getQName() + " not found.");
  +			}
  +			pMethod.addLine(pRow, "[" + index + "] = ", pData, "[" + (i+1) + "];");
  +		}
  +	}
  +	
  +	/** <p>Creates a method for cloning one row from the given table.</p>
  +	 */
  +	protected JavaMethod getInsertRowMethod(JavaSource pSource, TableInfo pTableInfo) {
  +		Table table = pTableInfo.getTable();
  +		JavaMethod jm = pSource.newJavaMethod(getInsertRowMethodName(pTableInfo),
  +				Object[].class, JavaSource.PRIVATE);
  +		jm.addThrows(SQLException.class);
  +		DirectAccessible connection = jm.addParam(Connection.class, "pConn");
  +		DirectAccessible map = jm.addParam(Map.class, "pMap");
  +		DirectAccessible values = jm.addParam(Object[].class, "pValue");
  +		
  +		logFinestEntering(jm, values);
  +		
  +		LocalJavaField baseKey = null;
  +		if (table.getPrimaryKey() != null) {
  +			baseKey = getCacheDataClassInstance(jm, pTableInfo,
  +					table.getPrimaryKey(), values);
  +			jm.addIf(map, ".containsKey(", baseKey, ")");
  +			logFinestExiting(jm, JavaSource.getQuoted("null (Already cloned)"));
  +			jm.addLine("return null;");
  +			jm.addEndIf();
  +		}
  +		
  +		for (Iterator iter = pTableInfo.getColumnUpdaters();  iter.hasNext();  ) {
  +			((ColumnUpdater) iter.next()).update(jm, pTableInfo, connection, map, values);
  +		}
  +		
  +		jm.addLine(jm.getName(), "(", connection, ", ", values, ");");
  +		
  +		if (baseKey != null) {
  +			LocalJavaField clonedKey = getCacheDataClassInstance(jm, pTableInfo,
  +					table.getPrimaryKey(),
  +					values);
  +			jm.addLine(map, ".put(", baseKey, ", ", clonedKey, ");");
  +		}
  +		
  +		
  +		// Clone objects referencing this object
  +		LocalJavaField referencedValues = null;
  +		for (Iterator referencingIter = tablesByOrder.iterator();  referencingIter.hasNext();  ) {
  +			TableInfo prevTableInfo = (TableInfo) referencingIter.next();
  +			Table prevTable = prevTableInfo.getTable();
  +			for (Iterator fkIter = prevTable.getForeignKeys();  fkIter.hasNext();  ) {
  +				ForeignKey fk = (ForeignKey) fkIter.next();
  +				if (fk.getReferencedTable().equals(table)) {
  +					if (referencedValues == null) {
  +						referencedValues = jm.newJavaField(Object[].class);
  +						referencedValues.addLine(baseKey, ".getValues()");
  +					}
  +					getSelectRowsCode(jm, prevTableInfo, fk, connection, map, referencedValues, false);
  +				}
  +			}
  +		}
  +		
  +		logFinestExiting(jm, values);
  +		jm.addLine("return ", values, ";");
  +		
  +		return jm;
  +	}
  +	
  +	/** <p>Creates a method for cloning one row from the given table.</p>
  +	 */
  +	protected JavaMethod getInnerInsertRowMethod(JavaSource pSource, TableInfo pTableInfo) {
  +		Table table = pTableInfo.getTable();
  +		JavaMethod jm = pSource.newJavaMethod(getInsertRowMethodName(pTableInfo),
  +				JavaQNameImpl.VOID, JavaSource.PRIVATE);
  +		jm.addThrows(SQLException.class);
  +		DirectAccessible connection = jm.addParam(Connection.class, "pConn");
  +		DirectAccessible values = jm.addParam(Object[].class, "pValue");
  +		
  +		logFinestEntering(jm, null);
  +		
  +		InsertStatement insertStatement = table.getInsertStatement();
  +		String s = table.getSchema().getSQLFactory().newSQLGenerator().getQuery(insertStatement);
  +		Object query = JavaSource.getQuoted(s);
  +		if (isGeneratingLogging()) {
  +			LocalJavaField q = jm.newJavaField(String.class);
  +			q.addLine(query);
  +			query = q;
  +			logFinest(jm, query, values);
  +		}
  +		LocalJavaField stmt = jm.newJavaField(PreparedStatement.class, "stmt");
  +		stmt.setFinal(true);
  +		stmt.addLine(connection, ".prepareStatement(", query, ");");
  +		LocalJavaField isStmtClosed = jm.newJavaField(boolean.class, "isStmtClosed");
  +		isStmtClosed.addLine("false");
  +		jm.addTry();
  +		
  +		int paramNum = 0;
  +		for (Iterator iter = table.getColumns();  iter.hasNext();  ) {
  +			Column column = (Column) iter.next();
  +			Object v = new Object[]{ values, "[", Integer.toString(paramNum), "]" };
  +			setPreparedStatementValue(jm, column, stmt, Integer.toString(++paramNum), v);
  +		}
  +		
  +		jm.addLine(stmt, ".executeUpdate();");
  +		jm.addLine(isStmtClosed, " = true;");
  +		jm.addLine(stmt, ".close();");
  +		
  +		jm.addFinally();
  +		jm.addIf("!", isStmtClosed);
  +		jm.addTry();
  +		jm.addLine(stmt, ".close();");
  +		jm.addCatch(Throwable.class, "ignore");
  +		jm.addEndTry();
  +		jm.addEndIf();
  +		jm.addEndTry();
  +		
  +		logFinestExiting(jm, null);
  +		return jm;
  +	}
  +	
  +	
  +	/** <p>Actually creates the public "clone" method.</p>
  +	 */
  +	protected JavaMethod getPublicCloneMethod(JavaSource pSource) {
  +		TableInfo headTable;
  +		{
  +			Iterator iter = tablesByOrder.iterator();
  +			if (!iter.hasNext()) {
  +				throw new IllegalStateException("No tables have been added.");
  +			}
  +			headTable = (TableInfo) iter.next();
  +		}
  +		
  +		JavaQName resultType = JavaQNameImpl.getInstance(Object[].class);
  +		JavaMethod jm = pSource.newJavaMethod("clone", resultType, JavaSource.PUBLIC);
  +		jm.addThrows(SQLException.class);
  +		JavaComment jc = jm.newComment();
  +		jc.addLine("<p>This method takes as input the key values of a row in the table " +
  +				headTable.getTable().getQName() + ".");
  +		jc.addLine("The key values are given by the array <code>pRow</code>:");
  +		jc.addLine("<ul>");
  +		int i = 0;
  +		for (Iterator iter = headTable.getTable().getPrimaryKey().getColumns();
  +				iter.hasNext();  i++) {
  +			Column col = (Column) iter.next();
  +			jc.addLine("  <li><code>pRow[" + i+ "] = " + col.getQName() + "</code></li>");
  +		}
  +		jc.addLine("</ul>");
  +		jc.addLine("The method updates the rows version number and creates a new row");
  +		jc.addLine("with the updated values.</p>");
  +		{
  +			Iterator iter = tablesByOrder.iterator();
  +			iter.next();
  +			if (iter.hasNext()) {
  +				jc.addLine("<p>Once the new row is created, the method searches for entries");
  +				jc.addLine("referencing the old row in the following tables:");
  +				jc.addLine("<table>");
  +				do {
  +					TableInfo subTable = (TableInfo) iter.next();
  +					jc.addLine("  <tr><td>" + subTable.getTable().getQName() + "</td></tr>");
  +				} while (iter.hasNext());
  +				jc.addLine("All the referencing entries are cloned as well, with updated");
  +				jc.addLine("references.");
  +			}
  +		}
  +		
  +		DirectAccessible conn = jm.addParam(Connection.class, "pConn");
  +		DirectAccessible row = jm.addParam(resultType, "pRow");
  +		
  +		logEntering(jm, new Object[]{"new ", Object[].class, "{", conn, ", ", row, "}"});
  +		
  +		LocalJavaField map = jm.newJavaField(Map.class, "clonedObjects");
  +		map.addLine("new ", HashMap.class, "()");
  +		
  +		getSelectRowsCode(jm, headTable, headTable.getTable().getPrimaryKey(),
  +				conn, map, row, true);
  +		return jm;
  +	}
  +	
  +	/** <p>Creates a method for updating one row in the head table.</p>
  +	 */
  +	public JavaMethod getCloneMethod(JavaSource pSource) {
  +		initLogging(pSource);
  +		
  +		for (Iterator iter = tablesByOrder.iterator();  iter.hasNext();  ) {
  +			TableInfo tableInfo = (TableInfo) iter.next();
  +			
  +			getInsertRowMethod(pSource, tableInfo);
  +			getInnerInsertRowMethod(pSource, tableInfo);
  +		}
  +		getCacheDataClass(pSource);
  +		getPublicCloneMethod(pSource);
  +		
  +		return null;
  +	}
   }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: jaxme-dev-unsubscribe@ws.apache.org
For additional commands, e-mail: jaxme-dev-help@ws.apache.org