/*


        ========== licence begin GPL
    Copyright (C) 2002-2003 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end


*/
package com.sap.dbtech.jdbc;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.sap.dbtech.jdbc.exceptions.DatabaseException;
import com.sap.dbtech.jdbc.exceptions.InternalJDBCError;
import com.sap.dbtech.jdbc.exceptions.InvalidArgumentValue;

/**
 * Database Meta Data base class.
 *
 * In this class,
 */
public abstract class DatabaseMetaDataBase implements DatabaseMetaData {
        protected ConnectionSapDB connection;
        protected boolean hasSchemaSupport;
        final static int dbmdResultSetType = ResultSet.TYPE_SCROLL_SENSITIVE;
        
        DatabaseMetaDataBase(ConnectionSapDB connection) {
                this.connection = connection;
                this.hasSchemaSupport = false;
        }

        public int getDefaultTransactionIsolation() throws SQLException {
                return Connection.TRANSACTION_READ_COMMITTED;
        }

        public int getDriverMajorVersion() {
                return DriverSapDB.singleton().getMajorVersion();
        }

        public int getDriverMinorVersion() {
                return DriverSapDB.singleton().getMinorVersion();
        }

        public int getJDBCMajorVersion() throws SQLException {
                return 3;
        }

        public int getJDBCMinorVersion() throws SQLException {
                return 0;
        }

        public int getMaxStatementLength() throws SQLException {
                return this.connection.maxStatementLength();
        }

        public int getMaxStatements() throws SQLException {
                return Integer.MAX_VALUE;
        }

        public String getNumericFunctions() throws SQLException {
                return "ABS,ACOS,ASIN,ATAN,ATAN2,CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,LOG10,MOD,PI,POWER,RADIANS,ROUND,SIGN,SIN,SQRT,TAN,TRUNCATE";
        }

        public String getProcedureTerm() throws SQLException {
                return "DBPROC";
        }

        public int getResultSetHoldability() throws SQLException {
                return ResultSet.HOLD_CURSORS_OVER_COMMIT;
        }

        public String getSchemaTerm() throws SQLException {
                return "SCHEMA";
        }

        public String getSearchStringEscape() throws SQLException {
                return "\\";
        }

        public String getSQLKeywords() throws SQLException {
                return "ABS,ACOS,ADDDATE,ADDTIME,ALPHA,ASCII,ASIN,ATAN,ATAN2,BINARY,BOOLEAN,BYTE,CEIL,CEILING,CHR,CONCAT,CONNECTED,COS,COSH,COT,CURDATE,CURTIME,DATABASE,DATEDIFF,DAYNAME,DAYOFMONTH,DAYOFWEEK,DAYOFYEAR,DBYTE,DECODE,DEFAULT,DEGREES,DIGITS,DIRECT,EBCDIC,ENTRY,ENTRYDEF,EXP,EXPAND,FIXED,FLOOR,GRAPHIC,GREATEST,HEX,IFNULL,INITCAP,INT,INTERNAL,LCASE,LEAST,LENGTH,LFILL,LINK,LIST,LN,LOCALSYSDBA,LOCATE,LOG,LOG10,LONG,LPAD,LTRIM,MAKEDATE,MAKETIME,MAPCHAR,MBCS,MICROSECOND,MOD,MONTHNAME,NOROUND,NOW,NUM,OBJECT,PACKED,PI,POWER,PREV,RADIANS,REAL,REFERENCED,REJECT,REPLACE,RFILL,ROUND,ROWID,ROWNO,RPAD,RTRIM,SELUPD,SHOW,SIGN,SIN,SINH,SOUNDEX,SPACE,SQRT,STAMP,STATISTICS,STDDEV,SUBDATE,SUBSTR,SUBTIME,SYSDBA,TAN,TANH,TIMEDIFF,TIMEZONE,TOIDENTIFIER,TRIM,TRUNC,TRUNCATE,UCASE,UNICODE,USERGROUP,VARGRAPHIC,VARIANCE,WEEK,WEEKOFYEAR,ZONED";
        }

        public String getStringFunctions() throws SQLException {
                return "ASCII,CONCAT,LCASE,LEFT,LENGTH,LOCATE,LOCATE_2,LTRIM,REPLACE,RIGHT,RTRIM,SOUNDEX,SPACE,SUBSTRING,UCASE,ISNULL";
        }

        public String getSystemFunctions() throws SQLException {
                return "DBNAME,IFNULL,USERNAME";
        }

        public int getSQLStateType() throws SQLException {
                return DatabaseMetaData.sqlStateSQL99;
        }

        public String getTimeDateFunctions() throws SQLException {
                return "CURDATE,CURTIME,DAYNAME,DAYOFMONTH,DAYOFWEEK,DAYOFYEAR,HOUR,MINUTE,MONTH,MONTHNAME,NOW,SECOND,WEEK,YEAR";
        }

        public String getURL() throws SQLException {
                return this.connection.getConnectProperty("dburl");
        }

        public String getUserName() throws SQLException {
                return this.connection.getConnectProperty("user");
        }

        public boolean insertsAreDetected(int type) throws SQLException {
                return false;
        }

        public boolean isCatalogAtStart() throws SQLException {
                return false;
        }

        public boolean isReadOnly() throws SQLException {
                return false;
        }

        public boolean locatorsUpdateCopy() throws SQLException {
                return false;
        }

        public boolean nullPlusNonNullIsNull() throws SQLException {
                return true;
        }

        public boolean nullsAreSortedAtEnd() throws SQLException {
                return false;
        }

        public boolean nullsAreSortedAtStart() throws SQLException {
                return false;
        }

        public boolean nullsAreSortedHigh() throws SQLException {
                return false;
        }

        public boolean nullsAreSortedLow() throws SQLException {
                return true;
        }

        public boolean othersDeletesAreVisible(int arg0) throws SQLException {
                return false;
        }

        public boolean othersInsertsAreVisible(int arg0) throws SQLException {
                return true;
        }

        public boolean othersUpdatesAreVisible(int arg0) throws SQLException {
                return true;
        }

        public boolean deletesAreDetected(int arg0) throws SQLException {
                return false;
        }

        public boolean ownDeletesAreVisible(int arg0) throws SQLException {
                return true;
        }

        public boolean ownInsertsAreVisible(int arg0) throws SQLException {
                return true;
        }

        public boolean ownUpdatesAreVisible(int arg0) throws SQLException {
                return true;
        }

        public boolean allProceduresAreCallable() throws SQLException {
                return false;
        }

        public boolean allTablesAreSelectable() throws SQLException {
                return false;
        }

        public boolean dataDefinitionCausesTransactionCommit()
                throws SQLException {
                return false;
        }

        public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
                return false;
        }

        public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
                return false;
        }

        public boolean storesLowerCaseIdentifiers() throws SQLException {
                return false;
        }

        public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
                return false;
        }

        public boolean storesMixedCaseIdentifiers() throws SQLException {
                return false;
        }

        public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
                return true;
        }

        public boolean storesUpperCaseIdentifiers() throws SQLException {
                return true;
        }

        public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
                return false;
        }

        public boolean supportsANSI92EntryLevelSQL() throws SQLException {
                return true;
        }

        public boolean supportsANSI92FullSQL() throws SQLException {
                return false;
        }

        public boolean supportsANSI92IntermediateSQL() throws SQLException {
                return false;
        }

        public boolean supportsAlterTableWithAddColumn() throws SQLException {
                return true;
        }

        public boolean supportsAlterTableWithDropColumn() throws SQLException {
                return true;
        }

        public boolean supportsBatchUpdates() throws SQLException {
                return true;
        }

        public boolean supportsCatalogsInDataManipulation() throws SQLException {
                return false;
        }

        public boolean supportsCatalogsInIndexDefinitions() throws SQLException {
                return false;
        }

        public boolean supportsCatalogsInPrivilegeDefinitions()
                throws SQLException {
                return false;
        }

        public boolean supportsCatalogsInProcedureCalls() throws SQLException {
                return false;
        }

        public boolean supportsCatalogsInTableDefinitions() throws SQLException {
                return false;
        }

        public boolean supportsColumnAliasing() throws SQLException {
                return true;
        }

        public boolean supportsConvert() throws SQLException {
                return false;
        }

        public boolean supportsConvert(int arg0, int arg1) throws SQLException {
                return false;
        }

        public boolean supportsCoreSQLGrammar() throws SQLException {
                return true;
        }

        public boolean supportsCorrelatedSubqueries() throws SQLException {
                return true;
        }

        public boolean supportsDataDefinitionAndDataManipulationTransactions()
                throws SQLException {
                return true;
        }

        public boolean supportsDataManipulationTransactionsOnly()
                throws SQLException {
                return false;
        }

        public boolean supportsDifferentTableCorrelationNames()
                throws SQLException {
                return false;
        }

        public boolean supportsExpressionsInOrderBy() throws SQLException {
                return true;
        }

        public boolean supportsExtendedSQLGrammar() throws SQLException {
                return true;
        }

        public boolean supportsFullOuterJoins() throws SQLException {
                return true;
        }

        public boolean supportsGetGeneratedKeys() throws SQLException {
                return false;
        }

        public boolean supportsGroupBy() throws SQLException {
                return true;
        }

        public boolean supportsGroupByBeyondSelect() throws SQLException {
                return false;
        }

        public boolean supportsGroupByUnrelated() throws SQLException {
                return true;
        }

        public boolean supportsIntegrityEnhancementFacility() throws SQLException {
                return true;
        }

        public boolean supportsLikeEscapeClause() throws SQLException {
                return true;
        }

        public boolean supportsLimitedOuterJoins() throws SQLException {
                return true;
        }

        public boolean supportsMinimumSQLGrammar() throws SQLException {
                return true;
        }

        public boolean supportsMixedCaseIdentifiers() throws SQLException {
                return false;
        }

        public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
                return true;
        }

        public boolean supportsMultipleOpenResults() throws SQLException {
                return false;
        }

        public boolean supportsMultipleResultSets() throws SQLException {
                return false;
        }

        public boolean supportsMultipleTransactions() throws SQLException {
                return true;
        }

        public boolean supportsNamedParameters() throws SQLException {
                return true;
        }

        public boolean supportsNonNullableColumns() throws SQLException {
                return true;
        }

        public boolean supportsOpenCursorsAcrossCommit() throws SQLException {
                return true;
        }

        public boolean supportsOpenCursorsAcrossRollback() throws SQLException {
                return true;
        }

        public boolean supportsOpenStatementsAcrossCommit() throws SQLException {
                return true;
        }

        public boolean supportsOpenStatementsAcrossRollback() throws SQLException {
                return true;
        }

        public boolean supportsOrderByUnrelated() throws SQLException {
                return true;
        }

        public boolean supportsOuterJoins() throws SQLException {
                return true;
        }

        public boolean supportsPositionedDelete() throws SQLException {
                return true;
        }

        public boolean supportsPositionedUpdate() throws SQLException {
                return true;
        }

        public boolean supportsSavepoints() throws SQLException {
                return true;
        }

        public boolean supportsResultSetConcurrency(int type, int concurrency)
                throws SQLException {
                switch (type) {
                        case java.sql.ResultSet.TYPE_FORWARD_ONLY :
                        case java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE :
                        case java.sql.ResultSet.TYPE_SCROLL_SENSITIVE :
                                break;
                        default :
                                throw new InvalidArgumentValue(
                                        "resultSetType",
                                        "TYPE_FORWARD_ONLY, TYPE_SCROLL_INSENSITIVE, TYPE_SCROLL_SENSITIVE");
                }
                switch (concurrency) {
                        case java.sql.ResultSet.CONCUR_READ_ONLY :
                        case java.sql.ResultSet.CONCUR_UPDATABLE :
                                // OK
                                break;
                        default :
                                throw new InvalidArgumentValue(
                                        "resultSetConcurrency",
                                        "CONCUR_READ_ONLY, CONCUR_UPDATABLE");
                }
                return true;
        }

        public String getCatalogTerm() throws SQLException {
                return "DATABASE";
        }

        public String getDatabaseProductName() throws SQLException {
                return DriverSapDB.driverName_C;
        }

        public String getCatalogSeparator() throws SQLException {
                return ".";
        }

        public boolean supportsResultSetHoldability(int holdability)
                throws java.sql.SQLException {
                return true;
        }

        public boolean supportsSchemasInDataManipulation() throws SQLException {
                return true; // user.table syntax
        }

        public boolean supportsSchemasInIndexDefinitions() throws SQLException {
                return true; // on user.tablename
        }

        public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException {
                return true; // with grant option on other users table.
        }

        public boolean supportsSchemasInProcedureCalls() throws SQLException {
                return true; // user.dbproc syntax
        }

        public boolean supportsSchemasInTableDefinitions() throws SQLException {
                return hasSchemaSupport;
        }

        public boolean supportsSelectForUpdate() throws SQLException {
                return true;
        }

        public boolean supportsStoredProcedures() throws SQLException {
            return true;
        }

        public boolean supportsSubqueriesInComparisons() throws SQLException {
            return true;
        }

        public boolean supportsSubqueriesInExists() throws SQLException {
            return true;
        }

        public boolean supportsSubqueriesInIns() throws SQLException {
            return true;
        }

        public boolean supportsSubqueriesInQuantifieds() throws SQLException {
            return true;
        }

        public boolean supportsTableCorrelationNames() throws SQLException {
            return true;
        }

        public boolean supportsTransactionIsolationLevel(int level) throws SQLException {
            if (level == Connection.TRANSACTION_NONE) {
                return false;
            }
            else {
                return true;
            }
        }

        public boolean supportsTransactions() throws SQLException {
            return true;
        }

        public boolean supportsUnion() throws SQLException {
            return true;
        }

        public boolean supportsUnionAll() throws SQLException {
            return true;
        }

        public boolean updatesAreDetected(int type) throws SQLException {
            return false;
        }

        public boolean usesLocalFilePerTable() throws SQLException {
            return false;
        }

        public boolean usesLocalFiles() throws SQLException {
            return false;
        }

        /**
             * JDBC 2.0
             *
             * Does the database support the given result set type?
             *
             * @param type defined in <code>java.sql.ResultSet</code>
             * @return <code>true</code> if so; <code>false</code> otherwise
             * @exception SQLException if a database access error occurs
             * @see Connection
             */
        public boolean supportsResultSetType(int type) throws SQLException {
            switch (type) {
                case java.sql.ResultSet.TYPE_FORWARD_ONLY:
                case java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE:
                case java.sql.ResultSet.TYPE_SCROLL_SENSITIVE:
                    break;
                default:
                    throw new InvalidArgumentValue ("resultSetType", "TYPE_FORWARD_ONLY, TYPE_SCROLL_INSENSITIVE, TYPE_SCROLL_SENSITIVE");
            }
            return true;
        }

        public boolean supportsStatementPooling() throws SQLException {
            return (this.connection.parseCache != null)?true:false;
          }

        public Connection getConnection() throws SQLException {
                return this.connection;
        }

        public String getExtraNameCharacters() throws SQLException {
                return "#@$";
        }

        public String getIdentifierQuoteString() throws SQLException {
                return "\"";
        }

        public abstract ResultSet getConstraints(
                String catalog,
                String schemapattern,
                String tablepattern)
                throws SQLException;

        /**
         *
         * @return java.sql.ResultSet
         * @param cmd java.lang.String
         * @param routine java.lang.String
         * @exception java.sql.SQLException The exception description.
         */
        protected ResultSet internalQuery(String cmd, String routine) throws SQLException {
            ResultSet result;
            com.sap.dbtech.util.Tracer.println("<Internal Query routine="+routine+" >\n"+cmd+"\n</Internal Query>\n");
            try {
                result = this.connection.createStatement(dbmdResultSetType, ResultSet.CONCUR_READ_ONLY).executeQuery (cmd);
                try { ((ResultSetSapDB)result).setFromMetaData(true); } catch(ClassCastException ccx) {}
            }
            catch (DatabaseException dbExc) {
                throw new InternalJDBCError (routine, dbExc);
            }
            return result;
        }

}
