view src/main/java/nl/cwi/monetdb/jdbc/MonetSavepoint.java @ 295:003ae6d881db

Add "final" keyword to method arguments and local variables where possible. It discovered some bugs in the MonetStatement constructor (changed the argument instead of object variable) which are fixed now. See also https://en.wikipedia.org/wiki/Final_(Java)
author Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
date Thu, 01 Aug 2019 20:18:43 +0200 (2019-08-01)
parents 92e882feea95
children c5efd6e661e5
line wrap: on
line source
/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0.  If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
 */

package nl.cwi.monetdb.jdbc;

import java.sql.SQLException;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * The representation of a savepoint, which is a point within the current
 * transaction that can be referenced from the Connection.rollback method.
 * When a transaction is rolled back to a savepoint all changes made after
 * that savepoint are undone.
 * Savepoints can be either named or unnamed. Unnamed savepoints are
 * identified by an ID generated by the underlying data source.
 *
 * This little class is nothing more than a container for a name and/or
 * an id. Each instance of this class always has an id, which is used for
 * internal representation of the save point.
 *
 * Because the IDs which get generated are a logical sequence, application
 * wide, two concurrent transactions are guaranteed to not to have the same
 * save point identifiers. In this implementation the validity of save points
 * is determined by the server, which makes this a light implementation.
 *
 * @author Fabian Groffen
 * @version 1.0
 */
public final class MonetSavepoint implements java.sql.Savepoint {
	/** The id of the last created Savepoint */
	private static final AtomicInteger highestId = new AtomicInteger(0);

	/** The name of this Savepoint */
	private final String name;
	/** The id of this Savepoint */
	private final int id;

	/**
	 * Creates a named MonetSavepoint object
	 */
	public MonetSavepoint(final String name) throws IllegalArgumentException {
		if (name == null || name.isEmpty())
			throw new IllegalArgumentException("missing savepoint name string");

		this.id = getNextId();
		this.name = name;
	}

	/**
	 * Creates an unnamed MonetSavepoint object
	 */
	public MonetSavepoint() {
		this.id = getNextId();
		this.name = null;
	}


	/**
	 * Retrieves the generated ID for the savepoint that this Savepoint object
	 * represents.
	 *
	 * @return the numeric ID of this savepoint
	 * @throws SQLException if this is a named savepoint
	 */
	@Override
	public int getSavepointId() throws SQLException {
		if (name != null)
			throw new SQLException("Cannot getID for named savepoint", "3B000");

		return id;
	}

	/**
	 * Retrieves the name of the savepoint that this Savepoint object
	 * represents.
	 *
	 * @return the name of this savepoint
	 * @throws SQLException if this is an un-named savepoint
	 */
	@Override
	public String getSavepointName() throws SQLException {
		if (name == null)
			throw new SQLException("Unable to retrieve name of unnamed savepoint", "3B000");

		return name;
	}

	//== end of methods from Savepoint interface

	/**
	 * Retrieves the savepoint id, like the getSavepointId method with the only
	 * difference that this method will always return the id, regardless of
	 * whether it is named or not.
	 *
	 * @return the numeric ID of this savepoint
	 */
	final int getId() {
		return id;
	}

	/**
	 * Returns the constructed internal name to use when referencing this save point to the
	 * MonetDB database. The returned value is guaranteed to be unique and consists of
	 * a prefix string and a sequence number.
	 *
	 * @return the unique savepoint name
	 */
	final String getName() {
		return "MonetDBSP" + id;
	}


	/**
	 * Returns the next id, which is larger than the last returned id. This
	 * method is synchronized to prevent race conditions. Since this is static
	 * code, this method is shared by requests from multiple Connection objects.
	 * Therefore two successive calls to this method need not to have a
	 * difference of 1.
	 *
	 * @return the next int which is guaranteed to be higher than the one
	 *         at the last call to this method.
	 */
	private static final int getNextId() {
		return highestId.incrementAndGet();
	}

	/**
	 * Returns the highest id returned by getNextId(). This method is also
	 * synchronized to prevent race conditions and thus guaranteed to be
	 * thread-safe.
	 *
	 * @return the highest id returned by a call to getNextId()
	 */
//	private static int getHighestId() {
//		return highestId.get();
//	}
}