001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdbc.sql;
012:
013: import com.versant.core.jdbc.JdbcKeyGenerator;
014: import com.versant.core.jdbc.JdbcKeyGeneratorFactory;
015: import com.versant.core.jdbc.JdbcMetaDataBuilder;
016: import com.versant.core.jdbc.metadata.JdbcTable;
017:
018: import java.sql.Connection;
019: import java.sql.SQLException;
020: import java.sql.Statement;
021: import java.util.HashSet;
022:
023: import com.versant.core.common.BindingSupportImpl;
024:
025: /**
026: * Key generator for classes using a database autoincrement or serial column
027: * for the primary key.
028: */
029: public class AutoIncJdbcKeyGenerator implements JdbcKeyGenerator {
030:
031: protected SqlDriver sqlDriver;
032:
033: /**
034: * Our factory.
035: */
036: public static class Factory implements JdbcKeyGeneratorFactory {
037:
038: /**
039: * Create a javabean to hold args for a createJdbcKeyGenerator call or null
040: * if the key generator does not accept any arguments.
041: */
042: public Object createArgsBean() {
043: return null;
044: }
045:
046: /**
047: * Create a JdbcKeyGenerator for class using props as parameters. The
048: * instance returned may be new or may be a shared instance.
049: */
050: public JdbcKeyGenerator createJdbcKeyGenerator(
051: String className, JdbcTable classTable, Object args) {
052: return new AutoIncJdbcKeyGenerator(className, classTable);
053: }
054: }
055:
056: public AutoIncJdbcKeyGenerator(String className,
057: JdbcTable classTable) {
058: if (classTable.pk.length > 1) {
059: throw BindingSupportImpl.getInstance().illegalArgument(
060: "Cannot use AUTOINC key generator on a table with multiple "
061: + "primary key columns: " + classTable.name
062: + " (" + className + ")");
063: }
064: sqlDriver = classTable.sqlDriver;
065: }
066:
067: /**
068: * Add any JdbcTable instances that this key generator requires to the
069: * supplied set. This method is called once per key generator during meta
070: * data generation. Any tables returned will be added to the meta data and
071: * will get into SQL scripts and so on. If the same key generator
072: * instance is returned more than once by a factory then this method
073: * will still only be called once on the instance.
074: */
075: public void addKeyGenTables(HashSet set, JdbcMetaDataBuilder mdb) {
076: // we do not use any extra tables
077: }
078:
079: /**
080: * If the new key can only be detirmined after the new row has been
081: * inserted (e.g. if using a database autoincrement column) then this
082: * should return true.
083: */
084: public boolean isPostInsertGenerator() {
085: return true;
086: }
087:
088: /**
089: * Get extra SQL to be appended to the insert statement. This is only
090: * called for post insert key generators. Return null if no extra SQL
091: * is required. Key generators can use this as an alternative to running
092: * a separate query to get the primary key for the just inserted row.
093: */
094: public String getPostInsertSQLSuffix(JdbcTable classTable) {
095: return sqlDriver.getAutoIncPostInsertSQLSuffix(classTable);
096: }
097:
098: /**
099: * Generate a new primary key value for a new instance of the supplied
100: * class after the row has been inserted. The values generated will be used
101: * to populate a new OID and then set on a PreparedStatement for the
102: * insert. This is called if isPostInsertGenerator returns true.
103: *
104: * @param className The name of the class
105: * @param classTable The table for the class
106: * @param data The array to store the key values in.
107: * @param con Connection to the DataSource for the class.
108: * @param stat Statement created from con. Do not close it. This will have
109: * just been used to insert the new row.
110: * @throws SQLException on errors
111: */
112: public void generatePrimaryKeyPost(String className,
113: JdbcTable classTable, Object[] data, Connection con,
114: Statement stat) throws SQLException {
115: data[0] = sqlDriver
116: .getAutoIncColumnValue(classTable, con, stat);
117: }
118:
119: /**
120: * Generate a new primary key value for a new instance of the supplied
121: * class prior to the row being inserted. The values generated will be used
122: * to populate a new OID and then set on a PreparedStatement for the
123: * insert. This is called if isPostInsertGenerator returns false.<p>
124: * <p/>
125: * The newObjectCount parameter indicates the number of new objects that
126: * will be inserted (including this one) in the same transaction using
127: * this key generator. This may be used to optimize the behavior of the
128: * key generator or be ignored. The highlow key generator uses this value
129: * instead of its grabSize to avoid executing redundant updates and
130: * selects.<p>
131: *
132: * @param className The name of the class
133: * @param classTable The table for the class
134: * @param newObjectCount The number of new objects being created
135: * @param data The array to store the key values in.
136: * @param con Connection to the DataSource for the class.
137: * @throws SQLException on errors
138: */
139: public void generatePrimaryKeyPre(String className,
140: JdbcTable classTable, int newObjectCount, Object[] data,
141: Connection con) throws SQLException {
142: throw BindingSupportImpl.getInstance().internal(
143: "generatePrimaryKeyPre called for "
144: + "post insert key generator");
145: }
146:
147: /**
148: * Initialize this key generator. This is called when the JDO
149: * implementation initializes before any keys are generated. Key
150: * generators should use this to avoid popular race conditions and
151: * deadlock opportunities (e.g. multiple 'select max(id) from table'
152: * statements executing at the same time). If the same key generator
153: * instance is used on more than one class this will be called once
154: * for each class.
155: *
156: * @param className The name of the class
157: * @param classTable The table for the class
158: * @param con Connection to the DataSource for the class
159: */
160: public void init(String className, JdbcTable classTable,
161: Connection con) throws SQLException {
162: // nothing to do
163: }
164:
165: /**
166: * Does this key generator require its own connection? If it does then
167: * one will be obtained to generate the key and committed after the
168: * key has been generated. This is called prior to every key generation
169: * call.
170: */
171: public boolean isRequiresOwnConnection() {
172: return false;
173: }
174:
175: }
|