001: /*
002: * This file or a portion of this file is licensed under the terms of
003: * the Globus Toolkit Public License, found in file ../GTPL, or at
004: * http://www.globus.org/toolkit/download/license.html. This notice must
005: * appear in redistributions of this file, with or without modification.
006: *
007: * Redistributions of this Software, with or without modification, must
008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
009: * some other similar material which is provided with the Software (if
010: * any).
011: *
012: * Copyright 1999-2004 University of Chicago and The University of
013: * Southern California. All rights reserved.
014: */
015: package org.griphyn.vdl.dbdriver;
016:
017: import org.griphyn.vdl.dbdriver.DatabaseDriver;
018: import java.sql.*;
019: import java.util.*;
020: import org.griphyn.vdl.util.*;
021:
022: /**
023: * This class implements the driver API for the MySQL 4.* database.
024: *
025: * @author Jens-S. Vöckler
026: * @author Yong Zhao
027: * @version $Revision: 50 $
028: *
029: * @see DatabaseDriver
030: * @see org.griphyn.vdl.dbschema
031: */
032: public class MySQL extends DatabaseDriver {
033: /**
034: * Maintains the property, if locking of sequence table is required.
035: */
036: boolean m_lockSequenceTable;
037:
038: /**
039: * Default constructor. As the constructor will do nothing, please use
040: * the connect method to obtain a database connection.
041: *
042: * @see #connect( String, Properties, Set )
043: */
044: public MySQL() {
045: super ();
046: m_lockSequenceTable = true;
047: }
048:
049: /**
050: * Establish a connection to your database. The parameters will often
051: * be ignored or abused for different purposes on different backends.
052: * It is assumed that the connection is not in auto-commit mode, and
053: * explicit commits must be issued.
054: *
055: * @param url the contact string to database, or schema location
056: * @param info additional parameters, usually username and password
057: * @param tables is a set of all table names in the schema. The
058: * existence of all tables will be checked to verify
059: * that the schema is active in the database.
060: * @return true if the connection succeeded, false otherwise. Usually,
061: * false is returned, if the any of the tables or sequences is missing.
062: * @exception SQLException if the driver is incapable of establishing
063: * a connection.
064: */
065: public boolean connect(String url, Properties info, Set tables)
066: throws SQLException, ClassNotFoundException {
067: // load MySQL driver class into memory
068: boolean save = this .connect("com.mysql.jdbc.Driver", url, info,
069: tables);
070:
071: // check for non-locking sequences
072: /* DO NOT DO THIS,
073: * because the PTC will always have several instances run in parallel.
074: * If necessary, use an extra property that is specifically linked to
075: * the combination of VDC and MySQL (argh, I want to avoid just that).
076: *
077: * String lock = info.getProperty( "lockSequenceTable", "true" );
078: * m_lockSequenceTable = Boolean.valueOf(lock).booleanValue();
079: */
080:
081: // add preparsed statement for sequence management
082: this .addPreparedStatement("vds.sequence.0",
083: "LOCK TABLE sequences WRITE");
084: this .addPreparedStatement("vds.sequence.1",
085: "UPDATE sequences SET currval=currval+1 WHERE name=?");
086: this .addPreparedStatement("vds.sequence.2",
087: "SELECT currval FROM sequences where name=?");
088: this .addPreparedStatement("vds.sequence.3", "UNLOCK TABLE");
089:
090: // done
091: return save;
092: }
093:
094: /**
095: * Determines, if the backend is expensive, and results should be cached.
096: * Ideally, this will move transparently into the backend itself.
097: * @return true if caching is advisable, false for no caching.
098: */
099: public boolean cachingMakesSense() {
100: return true;
101: }
102:
103: /**
104: * Quotes a string that may contain special SQL characters.
105: * @param s is the raw string.
106: * @return the quoted string, which may be just the input string.
107: */
108: public String quote(String s) {
109: if (s.indexOf('\'') != -1) {
110: StringBuffer result = new StringBuffer();
111: for (int i = 0; i < s.length(); ++i) {
112: char ch = s.charAt(i);
113: result.append(ch);
114: if (ch == '\'')
115: result.append(ch);
116: }
117: return result.toString();
118: } else {
119: return s;
120: }
121: }
122:
123: /**
124: * Obtains the next value from a sequence.
125: *
126: * @param name is the name of the sequence.
127: * @return the next sequence number.
128: * @exception SQLException if something goes wrong while fetching the
129: * new value.
130: */
131: public long sequence1(String name) throws SQLException {
132: PreparedStatement ps = null;
133: Logging.instance()
134: .log("sql", 2, "SELECT nextval(" + name + ")");
135: Logging.instance().log("xaction", 1, "START sequence " + name);
136:
137: // phase 1: lock sequence table
138: if (m_lockSequenceTable) {
139: ps = this .getPreparedStatement("vds.sequence.0");
140: ps.executeUpdate();
141: }
142:
143: // phase 2: increment sequence
144: ps = this .getPreparedStatement("vds.sequence.1");
145: ps.setString(1, name);
146: ps.executeUpdate();
147:
148: // phase 3: obtain new value
149: ps = this .getPreparedStatement("vds.sequence.2");
150: ps.setString(1, name);
151: ResultSet rs = ps.executeQuery();
152: rs.next();
153: long result = rs.getLong(1);
154: rs.close();
155:
156: // phase 4: unlock table
157: if (m_lockSequenceTable) {
158: ps = this .getPreparedStatement("vds.sequence.3");
159: ps.executeUpdate();
160: }
161:
162: // done
163: // ??? commit();
164: Logging.instance().log("xaction", 1,
165: "FINAL sequence " + name + " = " + result);
166: return result;
167: }
168:
169: /**
170: * Obtains the sequence value for the current statement. Sigh.
171: *
172: * @param s is a statment or prepared statement
173: * @param name is the name of the sequence.
174: * @param pos is the column number of the auto-increment column.
175: * @return the next sequence number.
176: * @exception SQLException if something goes wrong while fetching the
177: * new value.
178: */
179: public long sequence2(Statement s, String name, int pos)
180: throws SQLException {
181: return -1;
182: }
183:
184: /**
185: * Predicate to tell the schema, if using a string instead of number
186: * will result in the speedier index scans instead of sequential scans.
187: * PostGreSQL has this problem, but using strings in the place of
188: * integers may not be universally portable.
189: *
190: * @return true, if using strings instead of integers and bigints
191: * will yield better performance.
192: *
193: */
194: public boolean preferString() {
195: return false;
196: }
197: }
|