~ubuntu-branches/ubuntu/wily/libhibernate3-java/wily-proposed

« back to all changes in this revision

Viewing changes to src/org/hibernate/id/TableGenerator.java

  • Committer: Bazaar Package Importer
  • Author(s): Torsten Werner
  • Date: 2007-10-14 14:43:34 UTC
  • Revision ID: james.westby@ubuntu.com-20071014144334-eamc8i0q10gs1aro
Tags: upstream-3.2.5
ImportĀ upstreamĀ versionĀ 3.2.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//$Id: TableGenerator.java 11304 2007-03-19 22:06:45Z steve.ebersole@jboss.com $
 
2
package org.hibernate.id;
 
3
 
 
4
import java.io.Serializable;
 
5
import java.sql.Connection;
 
6
import java.sql.PreparedStatement;
 
7
import java.sql.ResultSet;
 
8
import java.sql.SQLException;
 
9
import java.sql.Types;
 
10
import java.util.Properties;
 
11
 
 
12
import org.apache.commons.logging.Log;
 
13
import org.apache.commons.logging.LogFactory;
 
14
import org.hibernate.HibernateException;
 
15
import org.hibernate.LockMode;
 
16
import org.hibernate.dialect.Dialect;
 
17
import org.hibernate.engine.SessionImplementor;
 
18
import org.hibernate.engine.TransactionHelper;
 
19
import org.hibernate.mapping.Table;
 
20
import org.hibernate.type.Type;
 
21
import org.hibernate.util.PropertiesHelper;
 
22
 
 
23
/**
 
24
 * An <tt>IdentifierGenerator</tt> that uses a database
 
25
 * table to store the last generated value. It is not
 
26
 * intended that applications use this strategy directly.
 
27
 * However, it may be used to build other (efficient)
 
28
 * strategies. The returned type is <tt>Integer</tt>.<br>
 
29
 * <br>
 
30
 * The hi value MUST be fetched in a seperate transaction
 
31
 * to the <tt>Session</tt> transaction so the generator must
 
32
 * be able to obtain a new connection and commit it. Hence
 
33
 * this implementation may not be used when Hibernate is
 
34
 * fetching connections  when the user is supplying
 
35
 * connections.<br>
 
36
 * <br>
 
37
 * The returned value is of type <tt>integer</tt>.<br>
 
38
 * <br>
 
39
 * Mapping parameters supported: table, column
 
40
 *
 
41
 * @see TableHiLoGenerator
 
42
 * @author Gavin King
 
43
 */
 
44
public class TableGenerator extends TransactionHelper
 
45
        implements PersistentIdentifierGenerator, Configurable {
 
46
        /* COLUMN and TABLE should be renamed but it would break the public API */
 
47
        /** The column parameter */
 
48
        public static final String COLUMN = "column";
 
49
        
 
50
        /** Default column name */
 
51
        public static final String DEFAULT_COLUMN_NAME = "next_hi";
 
52
        
 
53
        /** The table parameter */
 
54
        public static final String TABLE = "table";
 
55
        
 
56
        /** Default table name */       
 
57
        public static final String DEFAULT_TABLE_NAME = "hibernate_unique_key";
 
58
 
 
59
        private static final Log log = LogFactory.getLog(TableGenerator.class);
 
60
 
 
61
        private String tableName;
 
62
        private String columnName;
 
63
        private String query;
 
64
        private String update;
 
65
 
 
66
        public void configure(Type type, Properties params, Dialect dialect) {
 
67
 
 
68
                tableName = PropertiesHelper.getString(TABLE, params, DEFAULT_TABLE_NAME);
 
69
                columnName = PropertiesHelper.getString(COLUMN, params, DEFAULT_COLUMN_NAME);
 
70
                String schemaName = params.getProperty(SCHEMA);
 
71
                String catalogName = params.getProperty(CATALOG);
 
72
 
 
73
                if ( tableName.indexOf( '.' )<0 ) {
 
74
                        tableName = Table.qualify( catalogName, schemaName, tableName );
 
75
                }
 
76
 
 
77
                query = "select " + 
 
78
                        columnName + 
 
79
                        " from " + 
 
80
                        dialect.appendLockHint(LockMode.UPGRADE, tableName) +
 
81
                        dialect.getForUpdateString();
 
82
 
 
83
                update = "update " + 
 
84
                        tableName + 
 
85
                        " set " + 
 
86
                        columnName + 
 
87
                        " = ? where " + 
 
88
                        columnName + 
 
89
                        " = ?";
 
90
        }
 
91
 
 
92
        public synchronized Serializable generate(SessionImplementor session, Object object)
 
93
                throws HibernateException {
 
94
                int result = ( (Integer) doWorkInNewTransaction(session) ).intValue();
 
95
                return new Integer(result);
 
96
        }
 
97
 
 
98
 
 
99
        public String[] sqlCreateStrings(Dialect dialect) {
 
100
                return new String[] {
 
101
                        dialect.getCreateTableString() + " " + tableName + " ( " + columnName + " " + dialect.getTypeName(Types.INTEGER) + " )",
 
102
                        "insert into " + tableName + " values ( 0 )"
 
103
                };
 
104
        }
 
105
 
 
106
        public String[] sqlDropStrings(Dialect dialect) {
 
107
                StringBuffer sqlDropString = new StringBuffer( "drop table " );
 
108
                if ( dialect.supportsIfExistsBeforeTableName() ) {
 
109
                        sqlDropString.append( "if exists " );
 
110
                }
 
111
                sqlDropString.append( tableName ).append( dialect.getCascadeConstraintsString() );
 
112
                if ( dialect.supportsIfExistsAfterTableName() ) {
 
113
                        sqlDropString.append( " if exists" );
 
114
                }
 
115
                return new String[] { sqlDropString.toString() };
 
116
        }
 
117
 
 
118
        public Object generatorKey() {
 
119
                return tableName;
 
120
        }
 
121
 
 
122
        public Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException {
 
123
                int result;
 
124
                int rows;
 
125
                do {
 
126
                        // The loop ensures atomicity of the
 
127
                        // select + update even for no transaction
 
128
                        // or read committed isolation level
 
129
 
 
130
                        sql = query;
 
131
                        SQL.debug(query);
 
132
                        PreparedStatement qps = conn.prepareStatement(query);
 
133
                        try {
 
134
                                ResultSet rs = qps.executeQuery();
 
135
                                if ( !rs.next() ) {
 
136
                                        String err = "could not read a hi value - you need to populate the table: " + tableName;
 
137
                                        log.error(err);
 
138
                                        throw new IdentifierGenerationException(err);
 
139
                                }
 
140
                                result = rs.getInt(1);
 
141
                                rs.close();
 
142
                        }
 
143
                        catch (SQLException sqle) {
 
144
                                log.error("could not read a hi value", sqle);
 
145
                                throw sqle;
 
146
                        }
 
147
                        finally {
 
148
                                qps.close();
 
149
                        }
 
150
 
 
151
                        sql = update;
 
152
                        SQL.debug(update);
 
153
                        PreparedStatement ups = conn.prepareStatement(update);
 
154
                        try {
 
155
                                ups.setInt( 1, result + 1 );
 
156
                                ups.setInt( 2, result );
 
157
                                rows = ups.executeUpdate();
 
158
                        }
 
159
                        catch (SQLException sqle) {
 
160
                                log.error("could not update hi value in: " + tableName, sqle);
 
161
                                throw sqle;
 
162
                        }
 
163
                        finally {
 
164
                                ups.close();
 
165
                        }
 
166
                }
 
167
                while (rows==0);
 
168
                return new Integer(result);
 
169
        }
 
170
}