<commit_before>/*-------------------------------------------------------------------------
*
* Copyright (c) 2004-2008, PostgreSQL Global Development Group
*
* IDENTIFICATION
*   $PostgreSQL: pgjdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSetMetaData.java,v 1.23 2010/12/25 20:36:46 jurka Exp $
*
*-------------------------------------------------------------------------
*/
package org.postgresql.jdbc2;

import org.postgresql.PGResultSetMetaData;
import org.postgresql.core.*;
import org.postgresql.util.PSQLException;
import org.postgresql.util.PSQLState;
import java.sql.*;
import java.util.Hashtable;
import org.postgresql.util.GT;

public abstract class AbstractJdbc2ResultSetMetaData implements PGResultSetMetaData
{
    protected final BaseConnection connection;
    protected final Field[] fields;

    private boolean fieldInfoFetched;

    /*
     * Initialise for a result with a tuple set and
     * a field descriptor set
     *
     * @param fields the array of field descriptors
     */
    public AbstractJdbc2ResultSetMetaData(BaseConnection connection, Field[] fields)
    {
        this.connection = connection;
        this.fields = fields;
        fieldInfoFetched = false;
    }

    /*
     * Whats the number of columns in the ResultSet?
     *
     * @return the number
     * @exception SQLException if a database access error occurs
     */
    public int getColumnCount() throws SQLException
    {
        return fields.length;
    }

    /*
     * Is the column automatically numbered (and thus read-only)
     * I believe that PostgreSQL does not support this feature.
     *
     * @param column the first column is 1, the second is 2...
     * @return true if so
     * @exception SQLException if a database access error occurs
     */
    public boolean isAutoIncrement(int column) throws SQLException
    {
        fetchFieldMetaData();
        Field field = getField(column);
        return field.getAutoIncrement();
    }

    /*
     * Does a column's case matter? ASSUMPTION: Any field that is
     * not obviously case insensitive is assumed to be case sensitive
     *
     * @param column the first column is 1, the second is 2...
     * @return true if so
     * @exception SQLException if a database access error occurs
     */
    public boolean isCaseSensitive(int column) throws SQLException
    {
        Field field = getField(column);
        return connection.getTypeInfo().isCaseSensitive(field.getOID());
    }

    /*
     * Can the column be used in a WHERE clause?  Basically for
     * this, I split the functions into two types: recognised
     * types (which are always useable), and OTHER types (which
     * may or may not be useable). The OTHER types, for now, I
     * will assume they are useable.  We should really query the
     * catalog to see if they are useable.
     *
     * @param column the first column is 1, the second is 2...
     * @return true if they can be used in a WHERE clause
     * @exception SQLException if a database access error occurs
     */
    public boolean isSearchable(int column) throws SQLException
    {
        return true;
    }

    /*
     * Is the column a cash value? 6.1 introduced the cash/money
     * type, which haven't been incorporated as of 970414, so I
     * just check the type name for both 'cash' and 'money'
     *
     * @param column the first column is 1, the second is 2...
     * @return true if its a cash column
     * @exception SQLException if a database access error occurs
     */
    public boolean isCurrency(int column) throws SQLException
    {
        String type_name = getPGType(column);

        return type_name.equals("cash") || type_name.equals("money");
    }

    /*
     * Indicates the nullability of values in the designated column.
     *
     * @param column the first column is 1, the second is 2...
     * @return one of the columnNullable values
     * @exception SQLException if a database access error occurs
     */
    public int isNullable(int column) throws SQLException
    {
        fetchFieldMetaData();
        Field field = getField(column);
        return field.getNullable();
    }

    /*
     * Is the column a signed number? In PostgreSQL, all numbers
     * are signed, so this is trivial. However, strings are not
     * signed (duh!)
     *
     * @param column the first column is 1, the second is 2...
     * @return true if so
     * @exception SQLException if a database access error occurs
     */
    public boolean isSigned(int column) throws SQLException
    {
        Field field = getField(column);
        return connection.getTypeInfo().isSigned(field.getOID());
    }

    /*
     * What is the column's normal maximum width in characters?
     *
     * @param column the first column is 1, the second is 2, etc.
     * @return the maximum width
     * @exception SQLException if a database access error occurs
     */
    public int getColumnDisplaySize(int column) throws SQLException
    {
        Field field = getField(column);
        return connection.getTypeInfo().getDisplaySize(field.getOID(), field.getMod());
    }

    /*
     * @param column the first column is 1, the second is 2, etc.
     * @return the column label
     * @exception SQLException if a database access error occurs
     */
    public String getColumnLabel(int column) throws SQLException
    {
        Field field = getField(column);
        return field.getColumnLabel();
    }

    /*
     * What's a column's name?
     *
     * @param column the first column is 1, the second is 2, etc.
     * @return the column name
     * @exception SQLException if a database access error occurs
     */
    public String getColumnName(int column) throws SQLException
    {
        return getColumnLabel(column);
    }

    public String getBaseColumnName(int column) throws SQLException {
        fetchFieldMetaData();
        Field field = getField(column);
        return field.getColumnName();
    }

    /*
     * @param column the first column is 1, the second is 2...
     * @return the Schema Name
     * @exception SQLException if a database access error occurs
     */
    public String getSchemaName(int column) throws SQLException
    {
        return "";
    }

    private void fetchFieldMetaData() throws SQLException {
        if (fieldInfoFetched)
            return;

        fieldInfoFetched = true;

        StringBuffer sql = new StringBuffer();
        sql.append("SELECT c.oid, a.attnum, a.attname, c.relname, n.nspname, ");
        sql.append("a.attnotnull OR (t.typtype = 'd' AND t.typnotnull), ");
        sql.append("pg_catalog.pg_get_expr(d.adbin, d.adrelid) LIKE '%nextval(%' ");
        sql.append("FROM pg_catalog.pg_class c ");
        sql.append("JOIN pg_catalog.pg_namespace n ON (c.relnamespace = n.oid) ");
        sql.append("JOIN pg_catalog.pg_attribute a ON (c.oid = a.attrelid) ");
        sql.append("JOIN pg_catalog.pg_type t ON (a.atttypid = t.oid) ");
        sql.append("LEFT JOIN pg_catalog.pg_attrdef d ON (d.adrelid = a.attrelid AND d.adnum = a.attnum) ");
        sql.append("WHERE (c.oid, a.attnum) IN (");

        boolean hasSourceInfo = false;
        for (int i=0; i<fields.length; i++) {
            if (fields[i].getTableOid() == 0)
                continue;

            if (hasSourceInfo)
                sql.append(", ");
            else
                hasSourceInfo = true;

            sql.append("(");
            sql.append(fields[i].getTableOid());
            sql.append(", ");
            sql.append(fields[i].getPositionInTable());
            sql.append(")");
        }
        sql.append(")");

        if (!hasSourceInfo)
            return;
        
        Statement stmt = connection.createStatement();
        ResultSet rs = stmt.executeQuery(sql.toString());
        while (rs.next()) {
            int table = rs.getInt(1);
            int column = rs.getInt(2);
            String columnName = rs.getString(3);
            String tableName = rs.getString(4);
            String schemaName = rs.getString(5);
            int nullable = rs.getBoolean(6) ? ResultSetMetaData.columnNoNulls : ResultSetMetaData.columnNullable;
            boolean autoIncrement = rs.getBoolean(7);
            for (int i=0; i<fields.length; i++) {
                if (fields[i].getTableOid() == table && fields[i].getPositionInTable() == column) {
                    fields[i].setColumnName(columnName);
                    fields[i].setTableName(tableName);
                    fields[i].setSchemaName(schemaName);
                    fields[i].setNullable(nullable);
                    fields[i].setAutoIncrement(autoIncrement);
                }<commit_msg>Fixup fetching all metadata for a ResultSet at once for 7.4 servers. 7.4 does not support row IN operations (a,b) IN ((c,d),(e,f)).  So we've got to fake that with a JOIN.<commit_after>/*-------------------------------------------------------------------------
*
* Copyright (c) 2004-2008, PostgreSQL Global Development Group
*
* IDENTIFICATION
*   $PostgreSQL: pgjdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSetMetaData.java,v 1.24 2010/12/26 01:20:21 jurka Exp $
*
*-------------------------------------------------------------------------
*/
package org.postgresql.jdbc2;

import org.postgresql.PGResultSetMetaData;
import org.postgresql.core.*;
import org.postgresql.util.PSQLException;
import org.postgresql.util.PSQLState;
import java.sql.*;
import java.util.Hashtable;
import org.postgresql.util.GT;

public abstract class AbstractJdbc2ResultSetMetaData implements PGResultSetMetaData
{
    protected final BaseConnection connection;
    protected final Field[] fields;

    private boolean fieldInfoFetched;

    /*
     * Initialise for a result with a tuple set and
     * a field descriptor set
     *
     * @param fields the array of field descriptors
     */
    public AbstractJdbc2ResultSetMetaData(BaseConnection connection, Field[] fields)
    {
        this.connection = connection;
        this.fields = fields;
        fieldInfoFetched = false;
    }

    /*
     * Whats the number of columns in the ResultSet?
     *
     * @return the number
     * @exception SQLException if a database access error occurs
     */
    public int getColumnCount() throws SQLException
    {
        return fields.length;
    }

    /*
     * Is the column automatically numbered (and thus read-only)
     * I believe that PostgreSQL does not support this feature.
     *
     * @param column the first column is 1, the second is 2...
     * @return true if so
     * @exception SQLException if a database access error occurs
     */
    public boolean isAutoIncrement(int column) throws SQLException
    {
        fetchFieldMetaData();
        Field field = getField(column);
        return field.getAutoIncrement();
    }

    /*
     * Does a column's case matter? ASSUMPTION: Any field that is
     * not obviously case insensitive is assumed to be case sensitive
     *
     * @param column the first column is 1, the second is 2...
     * @return true if so
     * @exception SQLException if a database access error occurs
     */
    public boolean isCaseSensitive(int column) throws SQLException
    {
        Field field = getField(column);
        return connection.getTypeInfo().isCaseSensitive(field.getOID());
    }

    /*
     * Can the column be used in a WHERE clause?  Basically for
     * this, I split the functions into two types: recognised
     * types (which are always useable), and OTHER types (which
     * may or may not be useable). The OTHER types, for now, I
     * will assume they are useable.  We should really query the
     * catalog to see if they are useable.
     *
     * @param column the first column is 1, the second is 2...
     * @return true if they can be used in a WHERE clause
     * @exception SQLException if a database access error occurs
     */
    public boolean isSearchable(int column) throws SQLException
    {
        return true;
    }

    /*
     * Is the column a cash value? 6.1 introduced the cash/money
     * type, which haven't been incorporated as of 970414, so I
     * just check the type name for both 'cash' and 'money'
     *
     * @param column the first column is 1, the second is 2...
     * @return true if its a cash column
     * @exception SQLException if a database access error occurs
     */
    public boolean isCurrency(int column) throws SQLException
    {
        String type_name = getPGType(column);

        return type_name.equals("cash") || type_name.equals("money");
    }

    /*
     * Indicates the nullability of values in the designated column.
     *
     * @param column the first column is 1, the second is 2...
     * @return one of the columnNullable values
     * @exception SQLException if a database access error occurs
     */
    public int isNullable(int column) throws SQLException
    {
        fetchFieldMetaData();
        Field field = getField(column);
        return field.getNullable();
    }

    /*
     * Is the column a signed number? In PostgreSQL, all numbers
     * are signed, so this is trivial. However, strings are not
     * signed (duh!)
     *
     * @param column the first column is 1, the second is 2...
     * @return true if so
     * @exception SQLException if a database access error occurs
     */
    public boolean isSigned(int column) throws SQLException
    {
        Field field = getField(column);
        return connection.getTypeInfo().isSigned(field.getOID());
    }

    /*
     * What is the column's normal maximum width in characters?
     *
     * @param column the first column is 1, the second is 2, etc.
     * @return the maximum width
     * @exception SQLException if a database access error occurs
     */
    public int getColumnDisplaySize(int column) throws SQLException
    {
        Field field = getField(column);
        return connection.getTypeInfo().getDisplaySize(field.getOID(), field.getMod());
    }

    /*
     * @param column the first column is 1, the second is 2, etc.
     * @return the column label
     * @exception SQLException if a database access error occurs
     */
    public String getColumnLabel(int column) throws SQLException
    {
        Field field = getField(column);
        return field.getColumnLabel();
    }

    /*
     * What's a column's name?
     *
     * @param column the first column is 1, the second is 2, etc.
     * @return the column name
     * @exception SQLException if a database access error occurs
     */
    public String getColumnName(int column) throws SQLException
    {
        return getColumnLabel(column);
    }

    public String getBaseColumnName(int column) throws SQLException {
        fetchFieldMetaData();
        Field field = getField(column);
        return field.getColumnName();
    }

    /*
     * @param column the first column is 1, the second is 2...
     * @return the Schema Name
     * @exception SQLException if a database access error occurs
     */
    public String getSchemaName(int column) throws SQLException
    {
        return "";
    }

    private void fetchFieldMetaData() throws SQLException {
        if (fieldInfoFetched)
            return;

        fieldInfoFetched = true;

        StringBuffer sql = new StringBuffer();
        sql.append("SELECT c.oid, a.attnum, a.attname, c.relname, n.nspname, ");
        sql.append("a.attnotnull OR (t.typtype = 'd' AND t.typnotnull), ");
        sql.append("pg_catalog.pg_get_expr(d.adbin, d.adrelid) LIKE '%nextval(%' ");
        sql.append("FROM pg_catalog.pg_class c ");
        sql.append("JOIN pg_catalog.pg_namespace n ON (c.relnamespace = n.oid) ");
        sql.append("JOIN pg_catalog.pg_attribute a ON (c.oid = a.attrelid) ");
        sql.append("JOIN pg_catalog.pg_type t ON (a.atttypid = t.oid) ");
        sql.append("LEFT JOIN pg_catalog.pg_attrdef d ON (d.adrelid = a.attrelid AND d.adnum = a.attnum) ");
        sql.append("JOIN (");

        // 7.4 servers don't support row IN operations (a,b) IN ((c,d),(e,f))
        // so we've got to fake that with a JOIN here.
        //
        boolean hasSourceInfo = false;
        for (int i=0; i<fields.length; i++) {
            if (fields[i].getTableOid() == 0)
                continue;

            if (hasSourceInfo)
                sql.append(" UNION ALL ");

            sql.append("SELECT ");
            sql.append(fields[i].getTableOid());
            if (!hasSourceInfo)
                sql.append(" AS oid ");
            sql.append(", ");
            sql.append(fields[i].getPositionInTable());
            if (!hasSourceInfo)
                sql.append(" AS attnum");

            if (!hasSourceInfo)
                hasSourceInfo = true;
        }
        sql.append(") vals ON (c.oid = vals.oid AND a.attnum = vals.attnum) ");

        if (!hasSourceInfo)
            return;

        Statement stmt = connection.createStatement();
        ResultSet rs = stmt.executeQuery(sql.toString());
        while (rs.next()) {
            int table = rs.getInt(1);
            int column = rs.getInt(2);
            String columnName = rs.getString(3);
            String tableName = rs.getString(4);
            String schemaName = rs.getString(5);
            int nullable = rs.getBoolean(6) ? ResultSetMetaData.columnNoNulls : ResultSetMetaData.columnNullable;
            boolean autoIncrement = rs.getBoolean(7);
            for (int i=0; i<fields.length; i++) {
                if (fields[i].getTableOid() == table && fields[i].getPositionInTable() == column) {
                    fields[i].setColumnName(columnName);
                    fields[i].setTableName(tableName);
                    fields[i].setSchemaName(schemaName);
                    fields[i].setNullable(nullable);
                    fields[i].setAutoIncrement(autoIncrement);
                }
{'fraction_non_alphanumeric': 0.10965281283302485, 'fraction_numerical': 0.007964552134163442, 'mean_word_length': 2.2365220548193863, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, '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': '2557028', 'n_tokens_mistral': 4996, 'n_tokens_neox': 4818, 'n_words': 1614}