Hi,
I have a problem with the function "getGeneratedKeys()", it is either a mistake I do but do not see, or a bug.

I have two tables created as follows:
   private static final String typesTableCreationStr =
   "CREATE TABLE types (" +
   "  id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY," +
   "  name VARCHAR(128) NOT NULL UNIQUE," +
   "  shortName VARCHAR(64) NOT NULL" +
   ")";
   private static final String methodsTableCreationStr =
   "CREATE TABLE methods (" +
   "  id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY," +
   "  class INT REFERENCES types (id)," +
   "  name VARCHAR(128) NOT NULL," +
   "  isConstructor VARCHAR(5) NOT NULL," +
   "  isStatic VARCHAR(5) NOT NULL," +
   "  returnType INT REFERENCES types (id)" +
   ")";

I want to add an entry in table "methods" and retrieve the generated key (it works well with a simple INSERT INTO types). I have already 4 entries in table types with id 1, 2, 3, and 4; table methods is empty.
I do:
   private static final String insertStr_method =
   "INSERT INTO methods" +
   "  (class, name, isConstructor, isStatic, returnType)" +
   "  SELECT c.id, ?, ?, ?, r.id" +
   "  FROM types AS c" +
   "     , types AS r" +
   "  WHERE c.name = ?" +
   "    AND r.name = ?";
   ...
stmt = dbConnection.prepareStatement(insertStr_method, Statement.RETURN_GENERATED_KEYS);
       ...
       stmt.executeUpdate();
       ResultSet res = stmt.getGeneratedKeys();
       if ( res.next() ) {
         id = res.getInt(1);
         ...
       }
Then id equals 4. I would have expected 1 as it is the first insert into table methods. 4 is the last generated key of table "types" but the insert is done into table "methods", so I would have expected to get the last generated key of table "methods".
I am using db-derby-10.4.2.0 and jdk1.6.0_11 under Linux
I attached the java files I coded.

So, is it a bug or something I do wrong.

  Thank you,
  Gurvan
package org.thinkcollabs.jmbrowser.db;

import java.io.*;
import java.sql.*;
import java.util.*;


/**
 * This is a Data Accessor Object class.
 * An instance of this class is used to store and retrieve data objects from a database.
 * @author Nicolas Bonnel and Gurvan Le Guernic ({...@literal </a href="http://thinkcollabs.org";>ThinkCollabs</a>})
 */
class DAO {

    /** Path to the file containing configuration information (default to {...@value}) */
    private static final String propertiesFile = "./jmbrowser.cfg";
    /** Name of the property containing the driver to use ({...@value})*/
    private static final String dbDriver_propName = "DB_dbDriver";
    /** The default driver to use ({...@value})*/
    private static final String dbDriver_default = "org.apache.derby.jdbc.EmbeddedDriver";
    private static final String protocol_propName = "DB_protocol";
    private static final String protocol_default = "jdbc:derby:";
    private static final String dbName_propName = "DB_dbName";
    private static final String dbName_default = "JMBrowserDB";

    private static final String typesTableCreationStr =
	"CREATE TABLE types (" +
	"  id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY," +
	"  name VARCHAR(128) NOT NULL UNIQUE," +
	"  shortName VARCHAR(64) NOT NULL" +
	")";
    private static final String methodsTableCreationStr =
	"CREATE TABLE methods (" +
	"  id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY," +
	"  class INT REFERENCES types (id)," +
	"  name VARCHAR(128) NOT NULL," +
	"  isConstructor VARCHAR(5) NOT NULL," +
	"  isStatic VARCHAR(5) NOT NULL," +
	"  returnType INT REFERENCES types (id)" +
	")";
    private static final String methodParametersTableCreationStr =
	"CREATE TABLE methodParameters (" +
	"  method INT REFERENCES methods (id)," +
	"  position INT," +
	"  parameter INT REFERENCES types (id)" +
	")";

    private static final String insertStr_type =
	"INSERT INTO types" +
	"  (name, shortName)" +
	"  VALUES (?, ?)";
    private static final String insertStr_method =
	"INSERT INTO methods" +
	"  (class, name, isConstructor, isStatic, returnType)" +
	"  SELECT c.id, ?, ?, ?, r.id" +
	"  FROM types AS c" + 
	"     , types AS r" + 
	"  WHERE c.name = ?" +
	"    AND r.name = ?";
    private static final String insertStr_parameter =
	"INSERT INTO methodParameters" +
	"  (method, position, parameter)" +
	"  SELECT ?, ?, p.id" +
	"  FROM types AS p" + 
	"  WHERE p.name = ?";

    private Properties dbProperties;
    private Connection dbConnection;
    private String dbDriver;
    private String protocol;
    private String dbName;

    DAO() {
	loadDbProperties();
	loadDriver();
    }

    private boolean loadDbProperties() {
	boolean success = true;
	dbProperties = new Properties();
	dbProperties.setProperty(dbDriver_propName, dbDriver_default);
	dbProperties.setProperty(protocol_propName, protocol_default);
	dbProperties.setProperty(dbName_propName, dbName_default);
	InputStream is = null;
	try{
	    is = new FileInputStream(propertiesFile);
	    dbProperties.loadFromXML(is);
	    is.close();
	} catch (FileNotFoundException e) {
	    success = false;
	    System.out.println("Impossible to open file "+propertiesFile+".");
	} catch (SecurityException e) {
	    success = false;
	    System.out.println("Read access to file "+propertiesFile+" has been denied.");
	} catch (IOException e) {
	    success = false;
	    System.out.println("Problem loading properties from file "+propertiesFile+".");
	    /* e.printStackTrace(); */
	}
	dbDriver = dbProperties.getProperty(dbDriver_propName);
	protocol = dbProperties.getProperty(protocol_propName);
	dbName = dbProperties.getProperty(dbName_propName);
	System.out.println("Loaded the DB properties.");
	return success;
    }

    private boolean saveDbProperties() {
	boolean success = true;
	OutputStream os = null;
	try{
	    os = new FileOutputStream(propertiesFile);
	    dbProperties.storeToXML(os,null);
	    os.flush();
	    os.close();
	    System.out.println("Saved the DB properties into "+propertiesFile+".");
	} catch (FileNotFoundException e) {
	    success = false;
	    System.out.println("Impossible to open file "+propertiesFile+".");
	} catch (SecurityException e) {
	    success = false;
	    System.out.println("Write access to file "+propertiesFile+" has been denied.");
	} catch (IOException e) {
	    success = false;
	    System.out.println("Problem saving properties to file "+propertiesFile+".");
	    /* e.printStackTrace(); */
	}
	return success;
    }

    private void loadDriver() {
	try {
	    Class.forName(dbDriver).newInstance();
	    System.out.println("Loaded the DB driver.");
	} catch (ClassNotFoundException e) {
	    System.out.println("Unable to locate the class of DB driver '"+dbDriver+"'.");
	    System.out.println("Check your CLASSPATH!");
	    e.printStackTrace(System.err);
	} catch (InstantiationException e) {
	    System.out.println("Unable to instantiate the DB driver '"+dbDriver+"'.");
	    e.printStackTrace(System.err);
	} catch (IllegalAccessException e) {
	    System.out.println("Illegal access to the DB driver '"+dbDriver+"'.");
	    e.printStackTrace(System.err);
	}
    }

    private static void printSQLException(SQLException e) {
	System.out.println("SQL errors!");
	while (e != null) {
	    System.err.println("\n   --- SQL exception ---");
	    System.err.println(" SQL state: "+e.getSQLState());
	    System.err.println(" Error code: "+e.getErrorCode());
	    System.err.println(" Message: "+e.getMessage());
	    e = e.getNextException();
	}
    }

    public boolean createDB() {
	boolean successful = true;
	try {
	    dbConnection = DriverManager.getConnection(protocol + dbName + ";create=true");
	    Statement s = dbConnection.createStatement();
	    s.execute(typesTableCreationStr);
	    s.execute(methodsTableCreationStr);
	    s.execute(methodParametersTableCreationStr);
	} catch (java.sql.SQLException e) {
	    printSQLException(e);
	    successful = false;
	}
	System.out.println("DB created.");
	return successful;
    }

    public boolean loadDB() {
	boolean successful = true;
	try {
	    dbConnection = DriverManager.getConnection(protocol + dbName);
	} catch (java.sql.SQLException e) {
	    printSQLException(e);
	    successful = false;
	}
	System.out.println("DB loaded.");
	return successful;
    }

    public int insertType(String shortName, String name) {
	int id = -1;
	PreparedStatement stmt;
	try {
	    stmt = dbConnection.prepareStatement(insertStr_type, Statement.RETURN_GENERATED_KEYS);
	    stmt.setString(1, name);
	    stmt.setString(2, shortName);
	    stmt.executeUpdate();
	    ResultSet res = stmt.getGeneratedKeys();
	    if ( res.next() ) {
		id = res.getInt(1);
	    }
	} catch (java.sql.SQLException e) {
	    System.out.println("Error in DAO.insertType(String, String)");
	    printSQLException(e);
	}
	return id;
    }

    public int insertMethod(MethodRecord m) {
	int id = -1;
	PreparedStatement stmt;
	try {
	    stmt = dbConnection.prepareStatement(insertStr_method, Statement.RETURN_GENERATED_KEYS);
	    stmt.setString(1, m.getMethodName());
	    stmt.setString(2, Boolean.toString(m.isConstructor()));
	    stmt.setString(3, Boolean.toString(m.isStatic()));
	    stmt.setString(4, m.getClassName());
	    stmt.setString(5, m.getResultType());
	    stmt.executeUpdate();
	    ResultSet res = stmt.getGeneratedKeys();
	    if ( res.next() ) {
		id = res.getInt(1);
		stmt = dbConnection.prepareStatement(insertStr_parameter);
		Iterator<String> ite = m.getParameters().iterator();
		int i = 0;
		while ( ite.hasNext() ) {
		    String param = ite.next();
		    i = i + 1;
		    stmt.clearParameters();
		    System.out.println("\n P1 = " + id );
		    stmt.setInt(1, id);
		    System.out.println("\n P2 = " + i );
		    stmt.setInt(2, i);
		    System.out.println("\n P3 = " + param );
		    stmt.setString(3, param);
		    System.out.println("\n Stmt = " + stmt.getParameterMetaData() );
		    stmt.executeUpdate();
		    /* id = - id; */
		}
	    }
	} catch (java.sql.SQLException e) {
	    System.out.println("Error in DAO.insertMethod(MethodRecord)");
	    printSQLException(e);
	}
	return id;
    }

    private void displayTables() {
	try {
	    Statement stmt = dbConnection.createStatement();
	    ResultSet res;

	    System.out.println("\n   --- Table: types ---");
	    res = stmt.executeQuery("SELECT * FROM types");
	    while ( res.next() ) {
		System.out.print("id = " + res.getInt("id") + "; ");
		System.out.print("name = '" + res.getString("name") + "'; ");
		System.out.print("shortName = '" + res.getString("shortName") + "'");
		System.out.println();
	    }

	    System.out.println("\n   --- Table: methods ---");
	    res = stmt.executeQuery("SELECT * FROM methods");
	    while ( res.next() ) {
		System.out.print("id = " + res.getInt("id") + "; ");
		System.out.print("class = " + res.getInt("class") + "; ");
		System.out.print("name = '" + res.getString("name") + "'; ");
		System.out.print("isConstructor = '" + res.getString("isConstructor") + "'; ");
		System.out.print("isStatic = '" + res.getString("isStatic") + "'; ");
		System.out.print("returnType = " + res.getInt("returnType"));
		System.out.println();
	    }

	    System.out.println("\n   --- Table: methodParameters ---");
	    res = stmt.executeQuery("SELECT * FROM methodParameters");
	    while ( res.next() ) {
		System.out.print("method = " + res.getInt("method") + "; ");
		System.out.print("position = " + res.getInt("position") + "; ");
		System.out.print("parameter = " + res.getInt("parameter"));
		System.out.println();
	    }
	} catch (java.sql.SQLException e) {
	    System.out.println("Error in DAO.displayTables()");
	    printSQLException(e);
	}
    }

    public static void main(String[] arg) {
	DAO dao = new DAO();
	/* dao.saveDbProperties(); */
	File dbDir = new File(dao.dbName);
	if ( dbDir.isDirectory() ) {
	    dao.loadDB();
	} else {
	    if ( dbDir.exists() ) {
		System.out.println("Problem: a non-directory file as the same name as the DB.");
	    } else {
		dao.createDB();
	    }
	}
	dao.insertType("int", "int");
	dao.insertType("C1", "P.C1");
	dao.insertType("C2", "P.C2");
	dao.insertType("C3", "P.C3");
	String[] params = {"int", "P.C2"};
	dao.insertMethod(new MethodRecord(true, false, "P.C1", "P.C1", "C1", new Vector(Arrays.asList(params))));
	dao.displayTables();
    }
}
package org.thinkcollabs.jmbrowser.db;


import java.util.*;
import java.io.*;


/** 
 * Objects of this class represent method records to be stored into
 * (or retrieved from) the database.
 * @author Nicolas Bonnel and Gurvan Le Guernic (ThinkCollabs)
 */
public class MethodRecord implements Serializable {
    private boolean isConstructor;
    private boolean isStatic;
    private String result;
    private String className;
    private String methodName;
    private Vector<String> parameters;

    /**
     * Constructor of method record
     * @param constr must be true iff the method is a contructor
     * @param stat must be true iff the method is static
     * @param res full name of the type returned by the method
     * @param cn full name of the class of the method
     * @param mn method name
     * @param p vector of full name of parameters type
     */
    MethodRecord(boolean constr, boolean stat, String res, String cn, String mn, Vector<String> p) {
	isConstructor = constr;
	isStatic = stat;
	result = res;
	className = cn;
	methodName = mn;
	parameters = p;
    }

    /**
     * Test if the method is a constructor
     * @return true iff the method is a constructor
     */
    public boolean isConstructor() { return isConstructor; }

    /**
     * Test if the method is static
     * @return true iff the method is static
     */
    public boolean isStatic() { return isStatic; }

    /**
     * Accessor of the type of the result returned by the method.
     * @return a string corresponding to the full name of the type of the result
     */
    public String getResultType() { return result; }

    /**
     * Accessor of the class in which the method is declared.
     * @return a string corresponding to the full name of the class of the method
     */
    public String getClassName() { return className; }

    /**
     * Accessor of the name of the method
     * @return a string corresponding to the name of the method
     */
    public String getMethodName() { return methodName; }

    /**
     * Accessor of the method parameters
     * @return a vector of strings. Each string corresponds to the full name of the class of a parameter of the method
     */
    public Vector<String> getParameters() { return parameters; }

    /**
     * Transform an object of this class into a string describing it.
     * @return a string representing the object
     */
    public String toString() {
	String pStr = "";
	int nbParams = parameters.size();
	if (nbParams > 0) {	pStr = parameters.get(0); }
	for (int i = 1; i < nbParams; i++) {
	    pStr = pStr + ", " + parameters.get(i);
	}
	if (isConstructor) {
	    return ((String) "new " + className + "(" + pStr + ")");
	} else {
	    String staticStr = "";
	    if (isStatic) { staticStr = "static "; }
	    return ((String) staticStr + result + " " + className + "." + methodName + "(" + pStr + ")");
	}
    }
}

Reply via email to