All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData Maven / Gradle / Ivy

Go to download

Microsoft JDBC 4.2 Driver for SQL Server. The Azure Key Vault feature in Microsoft JDBC Driver for SQL Server depends on Azure SDK for JAVA and Azure Active Directory Library For Java.

There is a newer version: 12.8.1.jre11
Show newest version
//---------------------------------------------------------------------------------------------------------------------------------
// File: SQLServerDatabaseMetaData.java
//
//
// Microsoft JDBC Driver for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), 
//  to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//  and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
//  IN THE SOFTWARE.
//---------------------------------------------------------------------------------------------------------------------------------
 
 
package com.microsoft.sqlserver.jdbc;

import java.sql.*;
import java.util.*;
import java.text.*; 
import java.util.logging.*;

/**
* SQLServerDatabaseMetaData provides JDBC database meta data.
*
* The API javadoc for JDBC API methods that this class implements are not repeated here. Please
* see Sun's JDBC API interfaces javadoc for those details.
*/
public final class SQLServerDatabaseMetaData implements java.sql.DatabaseMetaData
{
    private SQLServerConnection connection;
    
    static final String urlprefix = "jdbc:sqlserver://";    
    
    static final private java.util.logging.Logger logger =
          java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerDatabaseMetaData");

    static final private java.util.logging.Logger loggerExternal =
        java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.DatabaseMetaData");
    
    static private int baseID = 0;	// Unique id generator for each  instance (used for logging).
    
    final private String traceID;
    
    // varbinary(max) https://msdn.microsoft.com/en-us/library/ms143432.aspx
    static final int MAXLOBSIZE = 2147483647;
    // uniqueidentifier https://msdn.microsoft.com/en-us/library/ms187942.aspx
    static final int uniqueidentifierSize = 36;
    
    enum CallableHandles
    {
        SP_COLUMNS                      ("{ call sp_columns(?, ?, ?, ?, ?) }", "{ call sp_columns_100(?, ?, ?, ?, ?, ?) }"),
        SP_COLUMN_PRIVILEGES ("{ call sp_column_privileges(?, ?, ?, ?)}", "{ call sp_column_privileges(?, ?, ?, ?)}"), 
        SP_TABLES                       ("{ call sp_tables(?, ?, ?, ?) }", "{ call sp_tables(?, ?, ?, ?) }"),
        SP_SPECIAL_COLUMNS      ("{ call sp_special_columns (?, ?, ?, ?, ?, ?, ?)}", "{ call sp_special_columns_100 (?, ?, ?, ?, ?, ?, ?)}"),
        SP_FKEYS                            ("{ call sp_fkeys (?, ?, ?, ? , ? ,?)}", "{ call sp_fkeys (?, ?, ?, ? , ? ,?)}"),
        SP_STATISTICS                   ("{ call sp_statistics(?,?,?,?,?, ?) }", "{ call sp_statistics_100(?,?,?,?,?, ?) }"),
        SP_SPROC_COLUMNS            ("{ call sp_sproc_columns(?, ?, ?,?,?) }", "{ call sp_sproc_columns_100(?, ?, ?,?,?) }"), 
        SP_STORED_PROCEDURES    ("{call sp_stored_procedures(?, ?, ?) }", "{call sp_stored_procedures(?, ?, ?) }"),
        SP_TABLE_PRIVILEGES         ("{call sp_table_privileges(?,?,?) }", "{call sp_table_privileges(?,?,?) }"), 
        SP_PKEYS                              ("{ call sp_pkeys (?, ?, ?)}", "{ call sp_pkeys (?, ?, ?)}");
		// stored procs before Katmai ie SS10
		private final String preKatProc;
		// procs on or after katmai
        private final String katProc;

        private CallableHandles(String name, String katName)
        {
            this.preKatProc = name;
            this.katProc = katName;
        }
        CallableStatement prepare(SQLServerConnection conn) throws SQLServerException
        {
            return conn.prepareCall(conn.isKatmaiOrLater()? katProc:preKatProc);
        }
    }
    
    final class  HandleAssociation 
    {
        final String databaseName;
        final CallableStatement stmt;
        HandleAssociation(String databaseName, CallableStatement stmt)
        {
            this.databaseName = databaseName;
            this.stmt = stmt;
        }
        final void close() throws SQLServerException
        {
            ((SQLServerCallableStatement)stmt).close();
        }
    } 
    EnumMap handleMap =
      new EnumMap(CallableHandles.class);

    

    // Returns unique id for each instance.
    private synchronized static int nextInstanceID()
    {
        baseID++;
        return baseID;
    }
    final public String toString()
    {
        return traceID;
    }
    
    /**
    * Create new database meta data
    * @param con the connection
    */
    /*L0*/ public SQLServerDatabaseMetaData(SQLServerConnection con) 
    {
        traceID = " SQLServerDatabaseMetaData:"  + nextInstanceID();
        connection = con;
        if(logger.isLoggable(java.util.logging.Level.FINE))
        {
            logger.fine(toString() + " created by (" + connection.toString() + ")");
        }
    }

    public boolean isWrapperFor(Class iface) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        // This class cannot be unwrapped
        return false;
    }

    public  T unwrap(Class iface) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        throw new SQLFeatureNotSupportedException(SQLServerException.getErrString("R_notSupported"));
    }

    private void checkClosed() throws SQLServerException 
    {
        if (connection.isClosed())
        {
            SQLServerException.makeFromDriverError(
                null,
                null,
                SQLServerException.getErrString("R_connectionIsClosed"),
                SQLServerException.EXCEPTION_XOPEN_CONNECTION_DOES_NOT_EXIST,
                false);
        }
    }

    private final static String ASC_OR_DESC = "ASC_OR_DESC";
    private final static String ATTR_NAME = "ATTR_NAME";
    private final static String ATTR_TYPE_NAME = "ATTR_TYPE_NAME";
    private final static String ATTR_SIZE = "ATTR_SIZE";
    private final static String ATTR_DEF = "ATTR_DEF";
    private final static String BASE_TYPE = "BASE_TYPE";
    private final static String BUFFER_LENGTH = "BUFFER_LENGTH";
    private final static String CARDINALITY = "CARDINALITY";
    private final static String CHAR_OCTET_LENGTH = "CHAR_OCTET_LENGTH";
    private final static String CLASS_NAME = "CLASS_NAME";
    private final static String COLUMN_DEF  = "COLUMN_DEF";
    private final static String COLUMN_NAME = "COLUMN_NAME";
    private final static String COLUMN_SIZE = "COLUMN_SIZE";
    private final static String COLUMN_TYPE = "COLUMN_TYPE";
    private final static String DATA_TYPE = "DATA_TYPE";
    private final static String DECIMAL_DIGITS = "DECIMAL_DIGITS";
    private final static String DEFERRABILITY = "DEFERRABILITY";
    private final static String DELETE_RULE = "DELETE_RULE";
    private final static String FILTER_CONDITION = "FILTER_CONDITION";
    private final static String FK_NAME = "FK_NAME";
    private final static String FKCOLUMN_NAME = "FKCOLUMN_NAME";
    private final static String FKTABLE_CAT = "FKTABLE_CAT";
    private final static String FKTABLE_NAME = "FKTABLE_NAME";
    private final static String FKTABLE_SCHEM = "FKTABLE_SCHEM";
    private final static String GRANTEE = "GRANTEE";
    private final static String GRANTOR = "GRANTOR";
    private final static String INDEX_NAME = "INDEX_NAME";
    private final static String INDEX_QUALIFIER = "INDEX_QUALIFIER";
    private final static String IS_GRANTABLE = "IS_GRANTABLE";
    private final static String IS_NULLABLE = "IS_NULLABLE";
    private final static String KEY_SEQ = "KEY_SEQ";
    private final static String LENGTH = "LENGTH";
    private final static String NON_UNIQUE = "NON_UNIQUE";
    private final static String NULLABLE = "NULLABLE";
    private final static String NUM_INPUT_PARAMS = "NUM_INPUT_PARAMS";
    private final static String NUM_OUTPUT_PARAMS = "NUM_OUTPUT_PARAMS";
    private final static String NUM_PREC_RADIX = "NUM_PREC_RADIX";
    private final static String NUM_RESULT_SETS = "NUM_RESULT_SETS";
    private final static String ORDINAL_POSITION = "ORDINAL_POSITION";
    private final static String PAGES = "PAGES";
    private final static String PK_NAME = "PK_NAME";
    private final static String PKCOLUMN_NAME = "PKCOLUMN_NAME";
    private final static String PKTABLE_CAT = "PKTABLE_CAT";
    private final static String PKTABLE_NAME = "PKTABLE_NAME";
    private final static String PKTABLE_SCHEM = "PKTABLE_SCHEM";
    private final static String PRECISION = "PRECISION";
    private final static String PRIVILEGE = "PRIVILEGE";
    private final static String PROCEDURE_CAT = "PROCEDURE_CAT";
    private final static String PROCEDURE_NAME = "PROCEDURE_NAME";
    private final static String PROCEDURE_SCHEM = "PROCEDURE_SCHEM";
    private final static String PROCEDURE_TYPE = "PROCEDURE_TYPE";
    private final static String PSEUDO_COLUMN = "PSEUDO_COLUMN";
    private final static String RADIX = "RADIX";
    private final static String REMARKS = "REMARKS";
    private final static String SCALE = "SCALE";
    private final static String SCOPE = "SCOPE";
    private final static String SCOPE_CATALOG = "SCOPE_CATALOG";
    private final static String SCOPE_SCHEMA = "SCOPE_SCHEMA";
    private final static String SCOPE_TABLE = "SCOPE_TABLE";
    private final static String SOURCE_DATA_TYPE = "SOURCE_DATA_TYPE";
    private final static String SQL_DATA_TYPE = "SQL_DATA_TYPE";
    private final static String SQL_DATETIME_SUB = "SQL_DATETIME_SUB";
    private final static String SS_DATA_TYPE = "SS_DATA_TYPE";
    private final static String SUPERTABLE_NAME = "SUPERTABLE_NAME";
    private final static String SUPERTYPE_CAT = "SUPERTYPE_CAT";
    private final static String SUPERTYPE_NAME = "SUPERTYPE_NAME";
    private final static String SUPERTYPE_SCHEM = "SUPERTYPE_SCHEM";
    private final static String TABLE_CAT = "TABLE_CAT";
    private final static String TABLE_NAME = "TABLE_NAME";
    private final static String TABLE_SCHEM = "TABLE_SCHEM";
    private final static String TABLE_TYPE = "TABLE_TYPE";
    private final static String TYPE = "TYPE";
    private final static String TYPE_CAT = "TYPE_CAT";
    private final static String TYPE_NAME = "TYPE_NAME";
    private final static String TYPE_SCHEM = "TYPE_SCHEM";
    private final static String UPDATE_RULE = "UPDATE_RULE";
    private final static String FUNCTION_CAT = "FUNCTION_CAT";
    private final static String FUNCTION_NAME = "FUNCTION_NAME";
    private final static String FUNCTION_SCHEM = "FUNCTION_SCHEM";
    private final static String FUNCTION_TYPE = "FUNCTION_TYPE";
    private final static String SS_IS_SPARSE = "SS_IS_SPARSE";
    private final static String SS_IS_COLUMN_SET = "SS_IS_COLUMN_SET";
    private final static String SS_IS_COMPUTED = "SS_IS_COMPUTED";
    private final static String IS_AUTOINCREMENT = "IS_AUTOINCREMENT";

    /**
    * Make a simple query execute and return the result from it. 
    * This is to be used only for internal queries without any user input.
    * @param catalog catalog the query to be made in
    * @param query to execute
    * @return Resultset from the execution
    */
    private final SQLServerResultSet getResultSetFromInternalQueries(String catalog, String query) throws SQLServerException
    {
        checkClosed();
        String orgCat = null;
        orgCat = switchCatalogs(catalog);
        SQLServerResultSet rs = null;
        try
        {
            rs = ((SQLServerStatement) connection.createStatement()).executeQueryInternal(query);
            
        }
        finally
        {
            if (null != orgCat) 
            {
                connection.setCatalog(orgCat);
            }
        }
        return rs;
    }

    
    /*
    *   Note we pool the handles per object. 
    */
    private CallableStatement getCallableStatementHandle(CallableHandles request, String catalog)  throws SQLServerException
    {
        CallableStatement CS = null;
        HandleAssociation hassoc = handleMap.get(request);
        if (null == hassoc 
            ||null == hassoc.databaseName
            || !hassoc.databaseName.equals(catalog))
        {
            CS = request.prepare(connection); 
            hassoc = new HandleAssociation(catalog, CS);
            HandleAssociation previous = handleMap.put(request, hassoc);
            if(null != previous)
            {
                previous.close();
            }
        }
        return hassoc.stmt;     
    }


    /**
    * Make the stored procedure call and return the result from it.
    * @param catalog catalog the query to be made in
    * @param procedure to execute
    * @param arguments for the stored procedure
    * @return Resultset from the execution
    */
    private final SQLServerResultSet getResultSetFromStoredProc(String catalog, CallableHandles procedure, String [] arguments) throws SQLServerException
    {
        checkClosed();
        assert null != arguments;
        String orgCat = null;
        orgCat = switchCatalogs(catalog); 
        SQLServerResultSet rs = null;
        try
        {
            SQLServerCallableStatement call = (SQLServerCallableStatement)getCallableStatementHandle(procedure, catalog);
            
            for (int i=1; i <= arguments.length; i++)
            {
                // note individual arguments can be null.
                call.setString(i, arguments[i-1]);
            }
            rs = (SQLServerResultSet)call.executeQueryInternal();
        }
        finally
        {
            if (null != orgCat) 
            {
                connection.setCatalog(orgCat);
            }
        }
        return rs;
    }

    private final SQLServerResultSet getResultSetWithProvidedColumnNames(String catalog,
        CallableHandles procedure, String[] arguments,   String[] columnNames) throws SQLServerException
    {
        // Execute the query
        SQLServerResultSet rs = getResultSetFromStoredProc(catalog, procedure, arguments);

        // Rename the columns
        for (int i = 0; i < columnNames.length; i++)
            rs.setColumnName(1+i, columnNames[i]);
        return rs;
    }

    /**
    * Switch database catalogs.
    * @param catalog the new catalog
    * @throws SQLServerException
    * @return the old catalog
    */
    /*L0*/ private String switchCatalogs(String catalog) throws SQLServerException {
     if (catalog == null)
       return null;
     String sCurr=null;
     sCurr = connection.getCatalog().trim();
     String sNew = catalog.trim();
     if (sCurr.equals(sNew))
       return null;
     connection.setCatalog(sNew);
     if (sCurr == null || sCurr.length()==0)
       return null;
     return sCurr;
    }

    /* -------------- JDBC Interface API starts here ---------------- */

    /*L0*/ public boolean allProceduresAreCallable() throws SQLServerException {
    checkClosed();
    return true;
    }

    /*L0*/ public boolean allTablesAreSelectable() throws SQLServerException {
    checkClosed();
    return true;
    }

    public boolean autoCommitFailureClosesAllResultSets() throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        checkClosed();
        return false;
    }

    /*L0*/ public boolean dataDefinitionCausesTransactionCommit() throws SQLServerException {
    checkClosed();
    return false;
    }

    /*L0*/ public boolean dataDefinitionIgnoredInTransactions() throws SQLServerException {
    checkClosed();
    return false;
    }

    /*L0*/ public boolean doesMaxRowSizeIncludeBlobs() throws SQLServerException {
    checkClosed();
    return false;
    }
    
	public boolean generatedKeyAlwaysReturned() throws SQLException
	{
    	DriverJDBCVersion.checkSupportsJDBC41();
        checkClosed();
    	
		// driver supports retrieving generated keys
        return true;	
	}		

	public long getMaxLogicalLobSize() throws SQLException
	{
    	DriverJDBCVersion.checkSupportsJDBC42();
        checkClosed();

    	return MAXLOBSIZE;
    }
	
	public boolean supportsRefCursors() throws SQLException
	{
    	DriverJDBCVersion.checkSupportsJDBC42();
        checkClosed();

    	return false;	
	}
	
    /*L0*/ public java.sql.ResultSet getCatalogs() throws SQLServerException {   	
    if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
    {
    	loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
    }
    checkClosed();
    // Return the orginal case instead of CAPS.removed Upper().
    String s  = "SELECT name AS TABLE_CAT FROM sys.databases order by name"; //Need to match case of connection.getCatalog
    return getResultSetFromInternalQueries(null,s);
    }

    /*L0*/ public String getCatalogSeparator() throws SQLServerException {
    checkClosed();
    return ".";
    }

    /*L0*/ public String getCatalogTerm() throws SQLServerException {
    checkClosed();
    return "database";
    }

    private final static String[] getColumnPrivilegesColumnNames =
    {
        /*1*/ TABLE_CAT,
        /*2*/ TABLE_SCHEM,
        /*3*/ TABLE_NAME,
        /*4*/ COLUMN_NAME,
        /*5*/ GRANTOR,
        /*6*/ GRANTEE,
        /*7*/ PRIVILEGE,
        /*8*/ IS_GRANTABLE
    };

    /*L0*/ public java.sql.ResultSet getColumnPrivileges(String catalog, String schema,
                                                 String table, String col) throws SQLServerException
    {
    	if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
        {
        	loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
        }
    	checkClosed();
        // column_privileges supports columns being escaped.
        col = EscapeIDName(col);
        /*
        sp_column_privileges [ @table_name = ] 'table_name' 
        [ , [ @table_owner = ] 'table_owner' ] 
        [ , [ @table_qualifier = ] 'table_qualifier' ] 
        [ , [ @column_name = ] 'column' ]*/
        
        String[]    arguments = new String[4];
        arguments[0] = table;
        arguments[1] = schema;
        arguments[2] = catalog;
        arguments[3] = col;
        return getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_COLUMN_PRIVILEGES, arguments, getColumnPrivilegesColumnNames);
    }

    private final static String[] getTablesColumnNames =
    {
        /*1*/ TABLE_CAT,
        /*2*/ TABLE_SCHEM,
        /*3*/ TABLE_NAME,
        /*4*/ TABLE_TYPE,
        /*5*/ REMARKS
    };

    /*L0*/ public java.sql.ResultSet getTables(String catalog, String schema, String table, String types[]) throws SQLServerException
    {
    	if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
        {
    		loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
        }
    	checkClosed();

        // sp_tables supports table name and owner ie schema escaped.
        table = EscapeIDName(table);
        schema = EscapeIDName(schema);
        /*        sp_tables [ [ @table_name = ] 'name' ] 
        [ , [ @table_owner = ] 'owner' ] 
        [ , [ @table_qualifier = ] 'qualifier' ] 
        [ , [ @table_type = ] "type" ]*/
        
        String[]    arguments = new String[4];
        arguments[0] = table;
        arguments[1] = schema;
        arguments[2] = catalog;
        
        String tableTypes =null;
        if (types != null) 
        {
            tableTypes ="'";
            for (int i=0; i 0)
                    tableTypes += ",";
                tableTypes += "''"+types[i] + "''";
            }
            tableTypes += "'";
        }
        arguments[3] = tableTypes;
        return getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_TABLES,arguments,  getTablesColumnNames);
    }

	static final char LEFT_BRACKET = '[';
    static final char RIGHT_BRACKET = ']';		
    static final char ESCAPE = '\\';		
    static final char PERCENT = '%';
    static final char UNDERSCORE = '_';
    static final char DOUBLE_RIGHT_BRACKET[] = { ']', ']' };
	
    /**
    * Accepts a SQL identifier (such as a column name or table name) and
    * escapes the identifier so sql 92 wild card characters can be escaped properly
    * to be passed to functions like sp_columns or sp_tables.
    * Assumes that the incoming identifier is unescaped.
    * @inID input identifier to escape.
    * @return the escaped value.
    */	
    private static String EscapeIDName(String inID) throws SQLServerException
    {
    if(null == inID)
    	return inID;
    // SQL bracket escaping rules.
    // See Using Wildcard Characters As Literals in SQL BOL
    // 
    // 	5\%		-> '5[%]'
    	//	\_n		->	'[_]n'		
    	//	\[		->  '[ [ ]'
    	//	\]		-> 	 ']'	
    	// 	\\		-> \
    	// 	\x		-> \x where x is any char other than the ones above.
    	
    char ch;
    // Add 2 extra chars wild guess thinking atleast one escape.
    StringBuilder outID = new StringBuilder(inID.length()+2);

    for(int i=0; i=0) 
    {
    	String name = info[index].name;

    	// making sure no security info is exposed.
    		if(!name.equals(SQLServerDriverBooleanProperty.INTEGRATED_SECURITY.toString()) && 
    			!name.equals(SQLServerDriverStringProperty.USER.toString()) &&
    			!name.equals(SQLServerDriverStringProperty.PASSWORD.toString()) &&
    			!name.equals(SQLServerDriverStringProperty.KEY_STORE_SECRET.toString())
    			)
    	{
    		String val = info[index].value;
            // skip empty strings
              if(0!= val.length())
              {
        		// special case these server name, instance name and port number as these go in the front  
        		if(name.equals(SQLServerDriverStringProperty.SERVER_NAME.toString()))
        		{
        			serverName = val;
        		}
        		else if (name.equals(SQLServerDriverStringProperty.INSTANCE_NAME.toString()))
        		{
        			instanceName = val;
        		}
        		else if( name.equals(SQLServerDriverIntProperty.PORT_NUMBER.toString()))
        		{
        			portNumber = val;
        		}
        		else
        		{
        			// build name value pairs separated by a semi colon
        			url.append(name);
        			url.append("=");
        			url.append(val);
        			url.append(";");
        		}
             }
    	}
    	
    }
    // insert the special items in the front in the reverse order. 
    // This way we will get the expected form as below.
    // MYSERVER\INSTANCEFOO:1433
    // port number first, we should always have port number
    url.insert(0,";");
    url.insert(0,portNumber);
    url.insert(0,":");
    if(null != instanceName)
    {
    	url.insert(0,instanceName);
    	url.insert(0,"\\");
    }
    url.insert(0,serverName);

    url.insert(0,urlprefix); // insert the prefix at the front.
    return (url.toString());
    }

    /*L0*/ public String getUserName() throws SQLServerException {
    if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
    {
        loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
    }
    checkClosed();
      SQLServerStatement s   = null;
      SQLServerResultSet rs  = null;
      String result = "";

      try {
         s  = (SQLServerStatement) connection.createStatement();
         rs = s.executeQueryInternal("select system_user");
         // Select system_user will always return a row.
         boolean next = rs.next();
         assert next;
         
         result = rs.getString(1);
      }
      finally {
         if (rs != null) {
            rs.close();
         }
         if (s != null) {
            s.close();
         }
      }
      return result;
    }

    private final static String[] getVersionColumnsColumnNames =
    {
        /*1*/ SCOPE,
        /*2*/ COLUMN_NAME,
        /*3*/ DATA_TYPE,
        /*4*/ TYPE_NAME,
        /*5*/ COLUMN_SIZE,
        /*6*/ BUFFER_LENGTH,
        /*7*/ DECIMAL_DIGITS,
        /*8*/ PSEUDO_COLUMN
    };

    /*L0*/ public java.sql.ResultSet getVersionColumns(String catalog, String schema,
                               String table) throws SQLServerException
    {
    	if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
        {
        	loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
        }
    	checkClosed();
        /*sp_special_columns [@table_name =] 'table_name'   
        [,[@table_owner =] 'table_owner'] 
        [,[@qualifier =] 'qualifier'] 
        [,[@col_type =] 'col_type'] 
        [,[@scope =] 'scope']
        [,[@nullable =] 'nullable'] 
        [,[@ODBCVer =] 'ODBCVer'] ;*/
        String[] arguments = new String[7];
        arguments[0] = table; 
        arguments[1] = schema;
        arguments[2] = catalog;
        arguments[3] = "V"; //col type
        arguments[4] = "T"; //scope
        arguments[5] = "U"; //nullable
        arguments[6] = "3"; //odbc ver
        SQLServerResultSet rs = getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_SPECIAL_COLUMNS,arguments,  getVersionColumnsColumnNames);

        // Hook in a filter on the DATA_TYPE column of the result set we're
        // going to return that converts the ODBC values from sp_columns
        // into JDBC values.
        rs.getColumn(3).setFilter(new DataTypeFilter());
        return rs;
    }

    /*L0*/ public boolean isCatalogAtStart() throws SQLServerException {
    checkClosed();
      return true;
    }

    /*L0*/ public boolean isReadOnly() throws SQLServerException {
    checkClosed();
     return false;
    }

    /*L0*/ public boolean nullPlusNonNullIsNull() throws SQLServerException {
    checkClosed();
     return true;
    }

    /*L0*/ public boolean nullsAreSortedAtEnd() throws SQLServerException {
    checkClosed();
      return false;
    }

    /*L0*/ public boolean nullsAreSortedAtStart() throws SQLServerException {
    checkClosed();
      return false;
    }

    /*L0*/ public boolean nullsAreSortedHigh() throws SQLServerException {
    checkClosed();
      return false;
    }

    /*L0*/ public boolean nullsAreSortedLow() throws SQLServerException {
    checkClosed();
      return true;
    }
    /*L0*/ public boolean storesLowerCaseIdentifiers() throws SQLServerException {
    checkClosed();
      return false;
    }

    /*L0*/ public boolean storesLowerCaseQuotedIdentifiers() throws SQLServerException {
    checkClosed();
      return false;
    }

    /*L0*/ public boolean storesMixedCaseIdentifiers() throws SQLServerException {
    checkClosed();
     return true;
    }

    /*L0*/ public boolean storesMixedCaseQuotedIdentifiers() throws SQLServerException {
    checkClosed();
      return true;
    }

    /*L0*/ public boolean storesUpperCaseIdentifiers() throws SQLServerException {
    checkClosed();
      return false;
    }

    /*L0*/ public boolean storesUpperCaseQuotedIdentifiers() throws SQLServerException {
    checkClosed();
      return false;
    }

    /*L0*/ public boolean supportsAlterTableWithAddColumn() throws SQLServerException {
    checkClosed();
      return true;
    }

    /*L0*/ public boolean supportsAlterTableWithDropColumn() throws SQLServerException {
    checkClosed();
      return true;
    }

    /*L0*/ public boolean supportsANSI92EntryLevelSQL() throws SQLServerException {
    checkClosed();
      return true;
    }

    /*L0*/ public boolean supportsANSI92FullSQL() throws SQLServerException {
      checkClosed();  return false;
    }

    /*L0*/ public boolean supportsANSI92IntermediateSQL() throws SQLServerException {
      checkClosed();  return false;
    }

    /*L0*/ public boolean supportsCatalogsInDataManipulation() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsCatalogsInIndexDefinitions() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsCatalogsInProcedureCalls() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsCatalogsInTableDefinitions() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsColumnAliasing() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsConvert() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsConvert(int fromType, int toType) throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsCoreSQLGrammar() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsCorrelatedSubqueries() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsDataDefinitionAndDataManipulationTransactions()  throws SQLServerException{
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsDataManipulationTransactionsOnly() throws SQLServerException {
      checkClosed();  return false;
    }

    /*L0*/ public boolean supportsDifferentTableCorrelationNames() throws SQLServerException {
      checkClosed();  return false;
    }

    /*L0*/ public boolean supportsExpressionsInOrderBy() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsExtendedSQLGrammar() throws SQLServerException {
      checkClosed();  return false;
    }

    /*L0*/ public boolean supportsFullOuterJoins() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsGroupBy() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsGroupByBeyondSelect() throws SQLServerException {
      checkClosed(); 
      return true;
    }

    /*L0*/ public boolean supportsGroupByUnrelated() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsIntegrityEnhancementFacility() throws SQLServerException {
      checkClosed();  
      return false;
    }


    /*L0*/ public boolean supportsLikeEscapeClause() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsLimitedOuterJoins() throws SQLServerException {
      checkClosed();  
      return true;
    }

    /*L0*/ public boolean supportsMinimumSQLGrammar() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsMixedCaseIdentifiers() throws SQLServerException    {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsMixedCaseQuotedIdentifiers() throws SQLServerException {
      checkClosed(); 
      return true;
    }

    /*L0*/ public boolean supportsMultipleResultSets() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsMultipleTransactions() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsNonNullableColumns() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsOpenCursorsAcrossCommit() throws SQLServerException {
      checkClosed();  
      return false;
    }

    /*L0*/ public boolean supportsOpenCursorsAcrossRollback() throws SQLServerException {
      checkClosed(); 
      return false;
    }
    /*L0*/ public boolean supportsOpenStatementsAcrossCommit() throws SQLServerException {
      checkClosed(); 
      return true;
    }

    /*L0*/ public boolean supportsOpenStatementsAcrossRollback() throws SQLServerException {
      checkClosed(); 
      return true;
    }

    /*L0*/ public boolean supportsOrderByUnrelated() throws SQLServerException {
      checkClosed();  
      return true;
    }

    /*L0*/ public boolean supportsOuterJoins() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsPositionedDelete() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsPositionedUpdate() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsSchemasInDataManipulation() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsSchemasInIndexDefinitions() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsSchemasInPrivilegeDefinitions() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsSchemasInProcedureCalls() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsSchemasInTableDefinitions() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsSelectForUpdate() throws SQLServerException {
    checkClosed();  
    return false;
    }

    /*L0*/ public boolean supportsStoredProcedures() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsSubqueriesInComparisons() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsSubqueriesInExists() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsSubqueriesInIns() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsSubqueriesInQuantifieds() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsTableCorrelationNames() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsTransactionIsolationLevel(int level) throws SQLServerException {
      checkClosed();  
    switch (level)
    	{
    	case Connection.TRANSACTION_READ_UNCOMMITTED:
    	case Connection.TRANSACTION_READ_COMMITTED:
    	case Connection.TRANSACTION_REPEATABLE_READ:
    	case Connection.TRANSACTION_SERIALIZABLE:
    	case SQLServerConnection.TRANSACTION_SNAPSHOT:
    		return true;
    	}
    return false;
    }

    /*L0*/ public boolean supportsTransactions() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsUnion() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean supportsUnionAll() throws SQLServerException {
      checkClosed();  return true;
    }

    /*L0*/ public boolean usesLocalFilePerTable() throws SQLServerException {
      checkClosed();  return false;
    }

    /*L0*/ public boolean usesLocalFiles() throws SQLServerException {
      checkClosed();  return false;
    }

    /*L0*/ public boolean supportsResultSetType(int type) throws SQLServerException {
      	checkClosed(); 
    checkResultType(type);
    switch (type)
    	{
    	case ResultSet.TYPE_FORWARD_ONLY:
    	case ResultSet.TYPE_SCROLL_INSENSITIVE:
    	case ResultSet.TYPE_SCROLL_SENSITIVE:
    	// case SQLServerResultSet.TYPE_SS_SCROLL_STATIC: insensitive synonym
    	// case SQLServerResultSet.TYPE_SS_SCROLL_KEYSET: sensitive synonym
    	case SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY:
    	case SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY:
    	case SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC:
    	return true;
    	}
      return false;
    }

    /*L0*/ public boolean supportsResultSetConcurrency(int type, int concurrency)  throws SQLServerException 
    {
    checkClosed();  
    checkResultType(type);
    checkConcurrencyType(concurrency);
    switch (type)
    	{
    	case ResultSet.TYPE_FORWARD_ONLY:
    	case ResultSet.TYPE_SCROLL_SENSITIVE: 
    	// case SQLServerResultSet.TYPE_SS_SCROLL_KEYSET: sensitive synonym
    	case SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC:
    	case SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY:
    		return true;
    	case ResultSet.TYPE_SCROLL_INSENSITIVE:
    	// case SQLServerResultSet.TYPE_SS_SCROLL_STATIC: sensitive synonym
    	case SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY:	
    		if(ResultSet.CONCUR_READ_ONLY == concurrency)
    			return true;
    		else
    			return false;
    	}
    // per spec if we do not know we do not support.
    return false;
    }

    /*L0*/ public boolean ownUpdatesAreVisible(int type) throws SQLServerException {
     	checkClosed();
    checkResultType(type);	 
    if (type==SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC || SQLServerResultSet.TYPE_FORWARD_ONLY==type ||
    	SQLServerResultSet.TYPE_SCROLL_SENSITIVE==type || SQLServerResultSet.TYPE_SS_SCROLL_KEYSET==type
    	|| SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY==type )
    	return true;
    return false;
    }

    /*L0*/ public boolean ownDeletesAreVisible(int type) throws SQLServerException {
      checkClosed();  
    checkResultType(type);
    if (type==SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC || SQLServerResultSet.TYPE_FORWARD_ONLY==type ||
    	SQLServerResultSet.TYPE_SCROLL_SENSITIVE==type || SQLServerResultSet.TYPE_SS_SCROLL_KEYSET==type
    	|| SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY==type )
    	return true;
    return false;
    }

    /*L0*/ public boolean ownInsertsAreVisible(int type) throws SQLServerException {
    checkClosed(); 
    checkResultType(type);
    if (type==SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC || SQLServerResultSet.TYPE_FORWARD_ONLY==type ||
    	SQLServerResultSet.TYPE_SCROLL_SENSITIVE==type || SQLServerResultSet.TYPE_SS_SCROLL_KEYSET==type
    	|| SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY==type)
    	return true;
    return false;
    }

    /*L0*/ public boolean othersUpdatesAreVisible(int type) throws SQLServerException {
     	checkClosed();
    checkResultType(type);
    if (type==SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC || SQLServerResultSet.TYPE_FORWARD_ONLY==type ||
    	SQLServerResultSet.TYPE_SCROLL_SENSITIVE==type || SQLServerResultSet.TYPE_SS_SCROLL_KEYSET==type
    	|| SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY==type  )
    	return true;
    return false;
    }

    /*L0*/ public boolean othersDeletesAreVisible(int type) throws SQLServerException {
    checkClosed();
    checkResultType(type);
    if (type==SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC || SQLServerResultSet.TYPE_FORWARD_ONLY==type ||
    	SQLServerResultSet.TYPE_SCROLL_SENSITIVE==type || SQLServerResultSet.TYPE_SS_SCROLL_KEYSET==type
    	|| SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY==type  )
    	return true;
     return false;
    }

    /*L0*/ public boolean othersInsertsAreVisible(int type) throws SQLServerException {
    checkClosed();
    checkResultType(type);
    if (type==SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC || SQLServerResultSet.TYPE_FORWARD_ONLY==type ||
    	 SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY==type )
    	return true;
    return false;
    }

    /*L0*/ public boolean updatesAreDetected(int type) throws SQLServerException {
    checkClosed();
    checkResultType(type);
     return false;
    }

    /*L0*/ public boolean deletesAreDetected(int type) throws SQLServerException 
    	{
    checkClosed();
    checkResultType(type);
    if (SQLServerResultSet.TYPE_SS_SCROLL_KEYSET == type)
    	return true;
    else
    	return false;
    }

    // Check the result types to make sure the user does not pass a bad value.
    /*L0*/ private void checkResultType(int type) throws SQLServerException 
    {
    	switch (type)
    	{
    		case ResultSet.TYPE_FORWARD_ONLY:
    		case ResultSet.TYPE_SCROLL_INSENSITIVE:
    		case ResultSet.TYPE_SCROLL_SENSITIVE:
    		//case SQLServerResultSet.TYPE_SS_SCROLL_STATIC: synonym TYPE_SCROLL_INSENSITIVE
    		//case SQLServerResultSet.TYPE_SS_SCROLL_KEYSET: synonym TYPE_SCROLL_SENSITIVE
    		case SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY:
    		case SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY:
    		case SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC:
    		return;
    	}
    	// if the value is outside of the valid values throw error.
    	MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidArgument"));
    	Object[] msgArgs = {new Integer(type)};
    	throw new SQLServerException(null , form.format(msgArgs) , null, 0 , true);	
    }

    // Check the concurrency values and make sure the value is a supported value. 
    /*L0*/ private void checkConcurrencyType(int type) throws SQLServerException 
    {
    	switch (type)
    	{
    		case ResultSet.CONCUR_READ_ONLY:
    		case ResultSet.CONCUR_UPDATABLE:
    		//case SQLServerResultSet.CONCUR_SS_OPTIMISTIC_CC: synonym CONCUR_UPDATABLE
    		case SQLServerResultSet.CONCUR_SS_SCROLL_LOCKS: 
    		case SQLServerResultSet.CONCUR_SS_OPTIMISTIC_CCVAL:
    		return;
    	}
    	// if the value is outside of the valid values throw error.
    	MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidArgument"));
    	Object[] msgArgs = {new Integer(type)};
    	throw new SQLServerException(null , form.format(msgArgs) , null, 0 , true);	
    }



    /*L0*/ public boolean insertsAreDetected(int type) throws SQLServerException {
    checkClosed();
    checkResultType(type);
     return false;
    }

    /*L0*/ public boolean supportsBatchUpdates() throws SQLServerException {
    checkClosed();
     return true;
    }

    /*L0*/ public java.sql.ResultSet getUDTs(String catalog, String schemaPattern,
                     String typeNamePattern, int[] types)  throws SQLServerException {
    if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
    {
        loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
    }
    checkClosed();
      return getResultSetFromInternalQueries(catalog, 
          "SELECT" +
          /*1*/ " cast(NULL as char(1)) as TYPE_CAT," +
          /*2*/ " cast(NULL as char(1)) as TYPE_SCHEM," +
          /*3*/ " cast(NULL as char(1)) as TYPE_NAME," +
          /*4*/ " cast(NULL as char(1)) as CLASS_NAME," +
          /*5*/ " cast(0 as int) as DATA_TYPE," +
          /*6*/ " cast(NULL as char(1)) as REMARKS," +
          /*7*/ " cast(0 as smallint) as BASE_TYPE" +
          " where 0 = 1");
    }

    /*L0*/ public java.sql.Connection getConnection() throws SQLServerException {
    checkClosed();
    return connection.getConnection();
    }

    /* JDBC 3.0 */

    /*L3*/ public int getSQLStateType() throws SQLServerException {
    checkClosed();
    if (connection != null && connection.xopenStates)
      return sqlStateXOpen;
    else
      return sqlStateSQL99;
    }

    /*L3*/ public int getDatabaseMajorVersion() throws SQLServerException {
    checkClosed();
    String s = connection.sqlServerVersion;
    int p = s.indexOf('.');
    if (p>0)
      s = s.substring(0, p);
    try {
      return new Integer(s).intValue();
    }
    catch (NumberFormatException e) {
      return 0;
    }
    }

    /*L3*/ public int getDatabaseMinorVersion() throws SQLServerException {
    checkClosed();
    String s = connection.sqlServerVersion;
    int p = s.indexOf('.');
    int q = s.indexOf('.', p+1);
    if (p>0 && q>0)
      s = s.substring(p+1, q);
    try {
      return new Integer(s).intValue();
    }
    catch (NumberFormatException e) {
      return 0;
    }
    }

    /*L3*/ public int getJDBCMajorVersion() throws SQLServerException {
    checkClosed();
	return DriverJDBCVersion.major;
    }
    /*L3*/ public int getJDBCMinorVersion() throws SQLServerException {
    checkClosed();  
	return DriverJDBCVersion.minor;
    }

    /*L3*/ public int getResultSetHoldability() throws SQLServerException {
    checkClosed();  return ResultSet.HOLD_CURSORS_OVER_COMMIT; //Hold over commit is the default for SQL Server
    }

    public RowIdLifetime getRowIdLifetime() throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        checkClosed();
        return RowIdLifetime.ROWID_UNSUPPORTED;
    }

    /*L3*/ public boolean supportsResultSetHoldability(int holdability)  throws SQLServerException 
    {
        checkClosed();  
        if (ResultSet.HOLD_CURSORS_OVER_COMMIT == holdability || ResultSet.CLOSE_CURSORS_AT_COMMIT == holdability)
        {
            return true; //supported one a per connection level only, not statement by statement
        }

        // if the value is outside of the valid values throw error.
        MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidArgument"));
        Object[] msgArgs = {new Integer(holdability)};
        throw new SQLServerException(null , form.format(msgArgs) , null, 0 , true);	
    }

    /*L3*/ public ResultSet getAttributes(String catalog, String schemaPattern,
                String typeNamePattern, String attributeNamePattern)  throws SQLServerException {
    if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
    {
        loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
    }
    checkClosed();
    return getResultSetFromInternalQueries(catalog, 
        "SELECT" +
        /* 1*/ " cast(NULL as char(1)) as TYPE_CAT," +
        /* 2*/ " cast(NULL as char(1)) as TYPE_SCHEM," +
        /* 3*/ " cast(NULL as char(1)) as TYPE_NAME," +
        /* 4*/ " cast(NULL as char(1)) as ATTR_NAME," +
        /* 5*/ " cast(0 as int) as DATA_TYPE," +
        /* 6*/ " cast(NULL as char(1)) as ATTR_TYPE_NAME," +
        /* 7*/ " cast(0 as int) as ATTR_SIZE," +
        /* 8*/ " cast(0 as int) as DECIMAL_DIGITS," +
        /* 9*/ " cast(0 as int) as NUM_PREC_RADIX," +
        /*10*/ " cast(0 as int) as NULLABLE," +
        /*11*/ " cast(NULL as char(1)) as REMARKS," +
        /*12*/ " cast(NULL as char(1)) as ATTR_DEF," +
        /*13*/ " cast(0 as int) as SQL_DATA_TYPE," +
        /*14*/ " cast(0 as int) as SQL_DATETIME_SUB," +
        /*15*/ " cast(0 as int) as CHAR_OCTET_LENGTH," +
        /*16*/ " cast(0 as int) as ORDINAL_POSITION," +
        /*17*/ " cast(NULL as char(1)) as IS_NULLABLE," +
        /*18*/ " cast(NULL as char(1)) as SCOPE_CATALOG," +
        /*19*/ " cast(NULL as char(1)) as SCOPE_SCHEMA," +
        /*20*/ " cast(NULL as char(1)) as SCOPE_TABLE," +
        /*21*/ " cast(0 as smallint) as SOURCE_DATA_TYPE" +
        " where 0 = 1");
    }

    /*L3*/ public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLServerException{
    if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
    {
        loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
    }
    checkClosed();
    return getResultSetFromInternalQueries(catalog, 
        "SELECT" +
        /*1*/ " cast(NULL as char(1)) as TYPE_CAT," +
        /*2*/ " cast(NULL as char(1)) as TYPE_SCHEM," +
        /*3*/ " cast(NULL as char(1)) as TYPE_NAME," +
        /*4*/ " cast(NULL as char(1)) as SUPERTABLE_NAME" +
        " where 0 = 1");
    }

    /*L3*/ public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLServerException {
    if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
    {
        loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
    }
    checkClosed();
    return getResultSetFromInternalQueries(catalog, 
        "SELECT" +
        /*1*/ " cast(NULL as char(1)) as TYPE_CAT," +
        /*2*/ " cast(NULL as char(1)) as TYPE_SCHEM," +
        /*3*/ " cast(NULL as char(1)) as TYPE_NAME," +
        /*4*/ " cast(NULL as char(1)) as SUPERTYPE_CAT," +
        /*5*/ " cast(NULL as char(1)) as SUPERTYPE_SCHEM," +
        /*6*/ " cast(NULL as char(1)) as SUPERTYPE_NAME" +
        " where 0 = 1");
    }

    /*L3*/ public boolean supportsGetGeneratedKeys() throws SQLServerException  {
    checkClosed();  return true;
    }

    /*L3*/ public boolean supportsMultipleOpenResults() throws SQLServerException  {
    checkClosed();  return false;
    }

    /*L3*/ public boolean supportsNamedParameters() throws SQLServerException  {
    checkClosed();  return true;
    }

    /*L3*/ public boolean supportsSavepoints() throws SQLServerException  {
    checkClosed();  return true;
    }
    /*L3*/ public boolean supportsStatementPooling()  throws SQLException {
    checkClosed();  
    return false;
    }

    public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        checkClosed();
        return true;
    }

    /*L3*/ public boolean locatorsUpdateCopy() throws SQLException {
    checkClosed();  return true;
    }
}

// Filter to convert DATA_TYPE column values from the ODBC types
// returned by SQL Server to their equivalent JDBC types.
final class DataTypeFilter extends IntColumnFilter
{
  private final static int ODBC_SQL_GUID         = -11;
  private final static int ODBC_SQL_WCHAR        = -8;
  private final static int ODBC_SQL_WVARCHAR     = -9;
  private final static int ODBC_SQL_WLONGVARCHAR = -10;
  private final static int ODBC_SQL_FLOAT = 6;	
  private final static int ODBC_SQL_TIME = -154;
  private final static int ODBC_SQL_XML = -152;
  private final static int ODBC_SQL_UDT = -151;
  
  
  int oneValueToAnother(int odbcType)
  {
    switch (odbcType)
    {
      case ODBC_SQL_FLOAT: return JDBCType.DOUBLE.asJavaSqlType();
      case ODBC_SQL_GUID: return JDBCType.CHAR.asJavaSqlType();
      case ODBC_SQL_WCHAR: return JDBCType.NCHAR.asJavaSqlType();
      case ODBC_SQL_WVARCHAR: return JDBCType.NVARCHAR.asJavaSqlType();
      case ODBC_SQL_WLONGVARCHAR: return JDBCType.LONGNVARCHAR.asJavaSqlType();
	  case ODBC_SQL_TIME: return JDBCType.TIME.asJavaSqlType();
	  case ODBC_SQL_XML: return SSType.XML.getJDBCType().asJavaSqlType();
      case ODBC_SQL_UDT: return SSType.UDT.getJDBCType().asJavaSqlType();
      
      default: return odbcType;
    }
  }

}

class ZeroFixupFilter extends IntColumnFilter
{
  int oneValueToAnother(int precl)
  {
    if (0==precl)
        return DataTypes.MAX_VARTYPE_MAX_BYTES;
	else
		return precl;
  }
}


// abstract class converts one value to another solely based on the column integer value
// apply to integer columns only
abstract class IntColumnFilter extends ColumnFilter
{
  abstract int oneValueToAnother(int value);

  final Object apply(Object value, JDBCType asJDBCType) throws SQLServerException
  {
	if(value==null)
		return value;
    // Assumption:  values will only be requested in integral or textual format
    // (i.e. not as float, double, BigDecimal, Boolean or bytes).  A request to return
    // a value as anything else results in an exception being thrown.

    switch (asJDBCType)
    {
      case INTEGER:
        return new Integer(oneValueToAnother(((Integer) value).intValue()));
      case SMALLINT: //small and tinyint returned as short
      case TINYINT:
        return new Short((short) oneValueToAnother(((Short) value).intValue()));
      case BIGINT:
        return new Long(oneValueToAnother(((Long) value).intValue()));
      case CHAR:
      case VARCHAR:
      case LONGVARCHAR:
        return Integer.toString(oneValueToAnother(Integer.parseInt((String) value)));
      default:
        DataTypes.throwConversionError("int", asJDBCType.toString());
        return value;
    }
  }

}

// Filter to convert int identity column values from 0,1 to YES, NO
// There is a mismatch between what the stored proc returns and what the 
// JDBC spec expects. 
class IntColumnIdentityFilter extends ColumnFilter
{
    private static final String zeroOneToYesNo(int i){return 0==i?"NO":"YES";}

    final Object apply(Object value, JDBCType asJDBCType) throws SQLServerException
    {
        if(value==null)
            return value;
        // Assumption:  values will only be requested in integral or textual format
        // (i.e. not as float, double, BigDecimal, Boolean or bytes).  A request to return
        // a value as anything else results in an exception being thrown.

        switch (asJDBCType)
        {
        	case INTEGER:
        	case SMALLINT:
                // This is a way for us to make getObject return a string, not an
                // integer. What this means is that getInt/getShort also will return a string.
                // However the identity column in the JDBC spec is supposed to return a 
                // string by default. To get to that default behavior right we are deliberately breaking
                // the getInt/getShort behavior which should really error anyways. Only thing is that 
                // the user will get a cast exception in this case.
        		assert (value instanceof Number);
        		return zeroOneToYesNo(((Number)value).intValue());                    
        	case CHAR:
            case VARCHAR:
            case LONGVARCHAR:
            	assert (value instanceof String);
            	return zeroOneToYesNo(Integer.parseInt((String)value));            	            	
            default:
                DataTypes.throwConversionError("char", asJDBCType.toString());
            return value;
        }
    }

}






© 2015 - 2024 Weber Informatics LLC | Privacy Policy