<commit_before>/*-------------------------------------------------------------------------
*
* Copyright (c) 2009-2014, PostgreSQL Global Development Group
*
*-------------------------------------------------------------------------
*/

package nl.topicus.jdbc.xa;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;

import javax.sql.XAConnection;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

import com.google.rpc.Code;

import nl.topicus.jdbc.CloudSpannerConnection;
import nl.topicus.jdbc.CloudSpannerPooledConnection;
import nl.topicus.jdbc.ICloudSpannerConnection;
import nl.topicus.jdbc.Logger;
import nl.topicus.jdbc.exception.CloudSpannerSQLException;

/**
 * The PostgreSQL implementation of {@link XAResource}.
 *
 * This implementation doesn't support transaction interleaving (see JTA
 * specification, section 3.4.4) and suspend/resume.
 *
 * Two-phase commit requires PostgreSQL server version 8.1 or higher.
 *
 * @author <NAME> (<EMAIL>)
 */
public class CloudSpannerXAConnection extends CloudSpannerPooledConnection implements XAConnection, XAResource
{
	/**
	 * A static flag that is used to checked whether the existence of the
	 * XA_PREPARED_MUTATIONS table has been checked
	 */
	private static boolean checkedTableExistence = false;

	private static final String CREATE_TABLE = "CREATE TABLE XA_PREPARED_MUTATIONS (XID STRING(150) NOT NULL, NUMBER INT64 NOT NULL, MUTATION STRING(MAX) NOT NULL) PRIMARY KEY (XID, NUMBER)";

	private static final String CHECK_TABLE_EXISTENCE = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=?";

	public static final String XA_PREPARED_MUTATIONS_TABLE = "XA_PREPARED_MUTATIONS";

	public static final String XA_XID_COLUMN = "XID";

	public static final String XA_NUMBER_COLUMN = "NUMBER";

	public static final String XA_MUTATION_COLUMN = "MUTATION";

	/**
	 * Underlying physical database connection. It's used for issuing PREPARE
	 * TRANSACTION/ COMMIT PREPARED/ROLLBACK PREPARED commands.
	 */
	private final CloudSpannerConnection conn;
	private final Logger logger;

	/*
	 * CloudSpannerXAConnection-object can be in one of three states:
	 *
	 * IDLE Not associated with a XA-transaction. You can still call
	 * getConnection and use the connection outside XA. currentXid is null.
	 * autoCommit is true on a connection by getConnection, per normal JDBC
	 * rules, though the caller can change it to false and manage transactions
	 * itself using Connection.commit and rollback.
	 *
	 * ACTIVE start has been called, and we're associated with an XA
	 * transaction. currentXid is valid. autoCommit is false on a connection
	 * returned by getConnection, and should not be messed with by the caller or
	 * the XA transaction will be broken.
	 *
	 * ENDED end has been called, but the transaction has not yet been prepared.
	 * currentXid is still valid. You shouldn't use the connection for anything
	 * else than issuing a XAResource.commit or rollback.
	 */
	private Xid currentXid;

	private int state;

	private static final int STATE_IDLE = 0;
	private static final int STATE_ACTIVE = 1;
	private static final int STATE_ENDED = 2;

	/*
	 * When an XA transaction is started, we put the underlying connection into
	 * non-autocommit mode. The old setting is saved in localAutoCommitMode, so
	 * that we can restore it when the XA transaction ends and the connection
	 * returns into local transaction mode.
	 */
	private boolean localAutoCommitMode = true;

	private void debug(String s)
	{
		logger.debug("XAResource " + Integer.toHexString(this.hashCode()) + ": " + s);
	}

	public CloudSpannerXAConnection(CloudSpannerConnection conn) throws SQLException
	{
		super(conn, true, true);
		this.conn = conn;
		this.state = STATE_IDLE;
		this.logger = conn.getLogger();
		checkAndCreateTable();
	}

	private void checkAndCreateTable() throws SQLException
	{
		if (!checkedTableExistence)
		{
			checkTableExistence(conn);
		}
	}

	private static synchronized void checkTableExistence(Connection conn) throws SQLException
	{
		if (checkedTableExistence)
			return;
		boolean createTable = false;
		try (PreparedStatement statement = conn.prepareStatement(CHECK_TABLE_EXISTENCE))
		{
			statement.setString(1, XA_PREPARED_MUTATIONS_TABLE);
			try (ResultSet rs = statement.executeQuery())
			{
				if (!rs.next())
				{
					createTable = true;
				}
			}
			if (createTable)
				createTable(conn);

			checkedTableExistence = true;
		}
	}

	private static synchronized void createTable(Connection conn) throws SQLException
	{
		try (PreparedStatement statement = conn.prepareStatement(CREATE_TABLE))
		{
			statement.executeUpdate();
		}
	}

	/****
	 * XAConnection interface
	 ****/

	@Override
	public ICloudSpannerConnection getConnection() throws SQLException
	{
		if (logger.logDebug())
		{
			debug("CloudSpannerXAConnection.getConnection called");
		}

		Connection conn = super.getConnection();

		// When we're outside an XA transaction, autocommit
		// is supposed to be true, per usual JDBC convention.
		// When an XA transaction is in progress, it should be
		// false.
		if (state == STATE_IDLE)
		{
			conn.setAutoCommit(true);
		}

		/*
		 * Wrap the connection in a proxy to forbid application from fiddling
		 * with transaction state directly during an XA transaction
		 */
		ConnectionHandler handler = new ConnectionHandler(conn);
		return (ICloudSpannerConnection) Proxy.newProxyInstance(getClass().getClassLoader(),
				new Class[] { Connection.class, ICloudSpannerConnection.class }, handler);
	}
<commit_msg>stop hiding the class field<commit_after>/*-------------------------------------------------------------------------
*
* Copyright (c) 2009-2014, PostgreSQL Global Development Group
*
*-------------------------------------------------------------------------
*/

package nl.topicus.jdbc.xa;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;

import javax.sql.XAConnection;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

import com.google.rpc.Code;

import nl.topicus.jdbc.CloudSpannerConnection;
import nl.topicus.jdbc.CloudSpannerPooledConnection;
import nl.topicus.jdbc.ICloudSpannerConnection;
import nl.topicus.jdbc.Logger;
import nl.topicus.jdbc.exception.CloudSpannerSQLException;

/**
 * The PostgreSQL implementation of {@link XAResource}.
 *
 * This implementation doesn't support transaction interleaving (see JTA
 * specification, section 3.4.4) and suspend/resume.
 *
 * Two-phase commit requires PostgreSQL server version 8.1 or higher.
 *
 * @author <NAME> (<EMAIL>)
 */
public class CloudSpannerXAConnection extends CloudSpannerPooledConnection implements XAConnection, XAResource
{
	/**
	 * A static flag that is used to checked whether the existence of the
	 * XA_PREPARED_MUTATIONS table has been checked
	 */
	private static boolean checkedTableExistence = false;

	private static final String CREATE_TABLE = "CREATE TABLE XA_PREPARED_MUTATIONS (XID STRING(150) NOT NULL, NUMBER INT64 NOT NULL, MUTATION STRING(MAX) NOT NULL) PRIMARY KEY (XID, NUMBER)";

	private static final String CHECK_TABLE_EXISTENCE = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=?";

	public static final String XA_PREPARED_MUTATIONS_TABLE = "XA_PREPARED_MUTATIONS";

	public static final String XA_XID_COLUMN = "XID";

	public static final String XA_NUMBER_COLUMN = "NUMBER";

	public static final String XA_MUTATION_COLUMN = "MUTATION";

	/**
	 * Underlying physical database connection. It's used for issuing PREPARE
	 * TRANSACTION/ COMMIT PREPARED/ROLLBACK PREPARED commands.
	 */
	private final CloudSpannerConnection conn;
	private final Logger logger;

	/*
	 * CloudSpannerXAConnection-object can be in one of three states:
	 *
	 * IDLE Not associated with a XA-transaction. You can still call
	 * getConnection and use the connection outside XA. currentXid is null.
	 * autoCommit is true on a connection by getConnection, per normal JDBC
	 * rules, though the caller can change it to false and manage transactions
	 * itself using Connection.commit and rollback.
	 *
	 * ACTIVE start has been called, and we're associated with an XA
	 * transaction. currentXid is valid. autoCommit is false on a connection
	 * returned by getConnection, and should not be messed with by the caller or
	 * the XA transaction will be broken.
	 *
	 * ENDED end has been called, but the transaction has not yet been prepared.
	 * currentXid is still valid. You shouldn't use the connection for anything
	 * else than issuing a XAResource.commit or rollback.
	 */
	private Xid currentXid;

	private int state;

	private static final int STATE_IDLE = 0;
	private static final int STATE_ACTIVE = 1;
	private static final int STATE_ENDED = 2;

	/*
	 * When an XA transaction is started, we put the underlying connection into
	 * non-autocommit mode. The old setting is saved in localAutoCommitMode, so
	 * that we can restore it when the XA transaction ends and the connection
	 * returns into local transaction mode.
	 */
	private boolean localAutoCommitMode = true;

	private void debug(String s)
	{
		logger.debug("XAResource " + Integer.toHexString(this.hashCode()) + ": " + s);
	}

	public CloudSpannerXAConnection(CloudSpannerConnection conn) throws SQLException
	{
		super(conn, true, true);
		this.conn = conn;
		this.state = STATE_IDLE;
		this.logger = conn.getLogger();
		checkAndCreateTable();
	}

	private void checkAndCreateTable() throws SQLException
	{
		if (!checkedTableExistence)
		{
			checkTableExistence(conn);
		}
	}

	private static synchronized void checkTableExistence(Connection conn) throws SQLException
	{
		if (checkedTableExistence)
			return;
		boolean createTable = false;
		try (PreparedStatement statement = conn.prepareStatement(CHECK_TABLE_EXISTENCE))
		{
			statement.setString(1, XA_PREPARED_MUTATIONS_TABLE);
			try (ResultSet rs = statement.executeQuery())
			{
				if (!rs.next())
				{
					createTable = true;
				}
			}
			if (createTable)
				createTable(conn);

			checkedTableExistence = true;
		}
	}

	private static synchronized void createTable(Connection conn) throws SQLException
	{
		try (PreparedStatement statement = conn.prepareStatement(CREATE_TABLE))
		{
			statement.executeUpdate();
		}
	}

	/****
	 * XAConnection interface
	 ****/

	@Override
	public ICloudSpannerConnection getConnection() throws SQLException
	{
		if (logger.logDebug())
		{
			debug("CloudSpannerXAConnection.getConnection called");
		}

		Connection connection = super.getConnection();

		// When we're outside an XA transaction, autocommit
		// is supposed to be true, per usual JDBC convention.
		// When an XA transaction is in progress, it should be
		// false.
		if (state == STATE_IDLE)
		{
			connection.setAutoCommit(true);
		}

		/*
		 * Wrap the connection in a proxy to forbid application from fiddling
		 * with transaction state directly during an XA transaction
		 */
		ConnectionHandler handler = new ConnectionHandler(connection);
		return (ICloudSpannerConnection) Proxy.newProxyInstance(getClass().getClassLoader(),
				new Class[] { Connection.class, ICloudSpannerConnection.class }, handler);
	}

{'fraction_non_alphanumeric': 0.10375275938189846, 'fraction_numerical': 0.0037357785702156563, 'mean_word_length': 3.8855246785566155, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6271172', 'n_tokens_mistral': 3669, 'n_tokens_neox': 3310, 'n_words': 1086}