/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com
*
*******************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
package org.pentaho.di.core.database;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.pentaho.di.core.row.value.ValueMetaBigNumber;
import org.pentaho.di.core.row.value.ValueMetaBinary;
import org.pentaho.di.core.row.value.ValueMetaBoolean;
import org.pentaho.di.core.row.value.ValueMetaDate;
import org.pentaho.di.core.row.value.ValueMetaInteger;
import org.pentaho.di.core.row.value.ValueMetaInternetAddress;
import org.pentaho.di.core.row.value.ValueMetaNumber;
import org.pentaho.di.core.row.value.ValueMetaString;
import org.pentaho.di.core.row.value.ValueMetaTimestamp;
public class MSAccessDatabaseMetaTest {
private MSAccessDatabaseMeta odbcMeta;
@Before
public void setupBefore() {
odbcMeta = new MSAccessDatabaseMeta();
odbcMeta.setAccessType( DatabaseMeta.TYPE_ACCESS_ODBC );
}
@Test
public void testSettings() throws Exception {
assertArrayEquals( new int[] { DatabaseMeta.TYPE_ACCESS_ODBC },
odbcMeta.getAccessTypeList() );
assertEquals( -1, odbcMeta.getDefaultDatabasePort() );
assertTrue( odbcMeta.supportsAutoInc() );
assertEquals( 1, odbcMeta.getNotFoundTK( true ) );
assertEquals( 0, odbcMeta.getNotFoundTK( false ) );
assertEquals( "sun.jdbc.odbc.JdbcOdbcDriver", odbcMeta.getDriverClass() );
assertEquals( "jdbc:odbc:FOO", odbcMeta.getURL( "IGNORED", "IGNORED", "FOO" ) );
assertFalse( odbcMeta.isFetchSizeSupported() );
assertFalse( odbcMeta.supportsBitmapIndex() );
assertFalse( odbcMeta.supportsSynonyms() );
assertFalse( odbcMeta.supportsSetCharacterStream() );
assertEquals( "[FOO].[BAR]", odbcMeta.getSchemaTableCombination( "FOO", "BAR" ) );
assertEquals( 65536, odbcMeta.getMaxTextFieldLength() );
assertFalse( odbcMeta.supportsTransactions() );
assertFalse( odbcMeta.supportsSetLong() );
assertFalse( odbcMeta.supportsGetBlob() );
assertFalse( odbcMeta.supportsViews() );
assertEquals( new String[] {
/*
* http://support.microsoft.com/kb/q109312 Note that if you set a reference to a type library, an object library,
* or an ActiveX control, that library's reserved words are also reserved words in your database. For example, if
* you add an ActiveX control to a form, a reference is set and the names of the objects, methods, and properties
* of that control become reserved words in your database. For existing objects with names that contain reserved
* words, you can avoid errors by surrounding the object name with brackets [ ], see
* getStartQuote(),getEndQuote().
*/
"ADD", "ALL", "ALPHANUMERIC", "ALTER", "AND", "ANY", "APPLICATION", "AS", "ASC", "ASSISTANT",
"AUTOINCREMENT", "AVG", "BETWEEN", "BINARY", "BIT", "BOOLEAN", "BY", "BYTE", "CHAR", "CHARACTER",
"COLUMN", "COMPACTDATABASE", "CONSTRAINT", "CONTAINER", "COUNT", "COUNTER", "CREATE", "CREATEDATABASE",
"CREATEFIELD", "CREATEGROUP", "CREATEINDEX", "CREATEOBJECT", "CREATEPROPERTY", "CREATERELATION",
"CREATETABLEDEF", "CREATEUSER", "CREATEWORKSPACE", "CURRENCY", "CURRENTUSER", "DATABASE", "DATE",
"DATETIME", "DELETE", "DESC", "DESCRIPTION", "DISALLOW", "DISTINCT", "DISTINCTROW", "DOCUMENT", "DOUBLE",
"DROP", "ECHO", "ELSE", "END", "EQV", "ERROR", "EXISTS", "EXIT", "FALSE", "FIELD", "FIELDS", "FILLCACHE",
"FLOAT", "FLOAT4", "FLOAT8", "FOREIGN", "FORM", "FORMS", "FROM", "FULL", "FUNCTION", "GENERAL",
"GETOBJECT", "GETOPTION", "GOTOPAGE", "GROUP", "GUID", "HAVING", "IDLE", "IEEEDOUBLE", "IEEESINGLE", "IF",
"IGNORE", "IMP", "IN", "INDEX", "INDEX", "INDEXES", "INNER", "INSERT", "INSERTTEXT", "INT", "INTEGER",
"INTEGER1", "INTEGER2", "INTEGER4", "INTO", "IS", "JOIN", "KEY", "LASTMODIFIED", "LEFT", "LEVEL", "LIKE",
"LOGICAL", "LOGICAL1", "LONG", "LONGBINARY", "LONGTEXT", "MACRO", "MATCH", "MAX", "MIN", "MOD", "MEMO",
"MODULE", "MONEY", "MOVE", "NAME", "NEWPASSWORD", "NO", "NOT", "NULL", "NUMBER", "NUMERIC", "OBJECT",
"OLEOBJECT", "OFF", "ON", "OPENRECORDSET", "OPTION", "OR", "ORDER", "OUTER", "OWNERACCESS", "PARAMETER",
"PARAMETERS", "PARTIAL", "PERCENT", "PIVOT", "PRIMARY", "PROCEDURE", "PROPERTY", "QUERIES", "QUERY",
"QUIT", "REAL", "RECALC", "RECORDSET", "REFERENCES", "REFRESH", "REFRESHLINK", "REGISTERDATABASE",
"RELATION", "REPAINT", "REPAIRDATABASE", "REPORT", "REPORTS", "REQUERY", "RIGHT", "SCREEN", "SECTION",
"SELECT", "SET", "SETFOCUS", "SETOPTION", "SHORT", "SINGLE", "SMALLINT", "SOME", "SQL", "STDEV", "STDEVP",
"STRING", "SUM", "TABLE", "TABLEDEF", "TABLEDEFS", "TABLEID", "TEXT", "TIME", "TIMESTAMP", "TOP",
"TRANSFORM", "TRUE", "TYPE", "UNION", "UNIQUE", "UPDATE", "USER", "VALUE", "VALUES", "VAR", "VARP",
"VARBINARY", "VARCHAR", "WHERE", "WITH", "WORKSPACE", "XOR", "YEAR", "YES", "YESNO" }, odbcMeta.getReservedWords() );
assertEquals( "[", odbcMeta.getStartQuote() );
assertEquals( "]", odbcMeta.getEndQuote() );
assertArrayEquals( new String[] {}, odbcMeta.getUsedLibraries() );
}
@Test
public void testSQLStatements() {
assertEquals( "DELETE FROM FOO",
odbcMeta.getTruncateTableStatement( "FOO" ) );
assertEquals( "ALTER TABLE FOO ADD COLUMN BAR TEXT(15)",
odbcMeta.getAddColumnStatement( "FOO", new ValueMetaString( "BAR", 15, 0 ), "", false, "", false ) );
assertEquals( "ALTER TABLE FOO DROP COLUMN BAR" + System.getProperty( "line.separator" ),
odbcMeta.getDropColumnStatement( "FOO", new ValueMetaString( "BAR", 15, 0 ), "", false, "", false ) );
assertEquals( "ALTER TABLE FOO ALTER COLUMN BAR TEXT(15)",
odbcMeta.getModifyColumnStatement( "FOO", new ValueMetaString( "BAR", 15, 0 ), "", false, "", false ) );
assertEquals( "insert into FOO(FOOVERSION) values (1)",
odbcMeta.getSQLInsertAutoIncUnknownDimensionRow( "FOO", "FOOKEY", "FOOVERSION" ) );
}
@Test
public void testGetFieldDefinition() {
assertEquals( "FOO DATETIME",
odbcMeta.getFieldDefinition( new ValueMetaDate( "FOO" ), "", "", false, true, false ) );
assertEquals( "DATETIME",
odbcMeta.getFieldDefinition( new ValueMetaTimestamp( "FOO" ), "", "", false, false, false ) );
assertFalse( odbcMeta.supportsBooleanDataType() );
assertEquals( "CHAR(1)",
odbcMeta.getFieldDefinition( new ValueMetaBoolean( "FOO" ), "", "", false, false, false ) );
odbcMeta.setSupportsBooleanDataType( true );
assertEquals( "BIT",
odbcMeta.getFieldDefinition( new ValueMetaBoolean( "FOO" ), "", "", false, false, false ) );
odbcMeta.setSupportsBooleanDataType( false );
// Key field Stuff
assertEquals( "COUNTER PRIMARY KEY",
odbcMeta.getFieldDefinition( new ValueMetaBigNumber( "FOO", 8, 0 ), "", "FOO", true, false, false ) );
assertEquals( "LONG PRIMARY KEY",
odbcMeta.getFieldDefinition( new ValueMetaNumber( "FOO", 10, 0 ), "FOO", "", false, false, false ) );
assertEquals( "LONG PRIMARY KEY",
odbcMeta.getFieldDefinition( new ValueMetaBigNumber( "FOO", 8, 0 ), "", "FOO", false, false, false ) );
// Integer types
assertEquals( "INTEGER",
odbcMeta.getFieldDefinition( new ValueMetaInteger( "FOO", 4, 0 ), "", "", false, false, false ) );
assertEquals( "LONG",
odbcMeta.getFieldDefinition( new ValueMetaNumber( "FOO", 6, 0 ), "", "", false, false, false ) );
assertEquals( "LONG",
odbcMeta.getFieldDefinition( new ValueMetaNumber( "FOO", 9, 0 ), "", "", false, false, false ) );
assertEquals( "DOUBLE",
odbcMeta.getFieldDefinition( new ValueMetaBigNumber( "FOO", 10, 0 ), "", "", false, false, false ) );
// Number Types ( as written, precision != 0 )
assertEquals( "DOUBLE",
odbcMeta.getFieldDefinition( new ValueMetaBigNumber( "FOO", 10, 1 ), "", "", false, false, false ) );
assertEquals( "DOUBLE",
odbcMeta.getFieldDefinition( new ValueMetaBigNumber( "FOO", 3, 1 ), "", "", false, false, false ) );
assertEquals( "DOUBLE",
odbcMeta.getFieldDefinition( new ValueMetaBigNumber( "FOO", 3, -5 ), "", "", false, false, false ) );
assertEquals( "DOUBLE",
odbcMeta.getFieldDefinition( new ValueMetaBigNumber( "FOO", -3, -5 ), "", "", false, false, false ) );
// String Types
assertEquals( "TEXT(255)",
odbcMeta.getFieldDefinition( new ValueMetaString( "FOO", 255, 0 ), "", "", false, false, false ) ); // Likely a bug - the maxTextFieldLength is set to 65536 - so this limitation is likely wrong
assertEquals( "TEXT(1)",
odbcMeta.getFieldDefinition( new ValueMetaString( "FOO", 1, 0 ), "", "", false, false, false ) );
assertEquals( "MEMO",
odbcMeta.getFieldDefinition( new ValueMetaString( "FOO", 256, 0 ), "", "", false, false, false ) );
assertEquals( "TEXT",
odbcMeta.getFieldDefinition( new ValueMetaString( "FOO", 0, 0 ), "", "", false, false, false ) );
assertEquals( "TEXT",
odbcMeta.getFieldDefinition( new ValueMetaString( "FOO" ), "", "", false, false, false ) );
// Other Types
assertEquals( " LONGBINARY",
odbcMeta.getFieldDefinition( new ValueMetaBinary( "FOO", 200, 1 ), "", "", false, false, false ) );
// Unknowns
assertEquals( " UNKNOWN",
odbcMeta.getFieldDefinition( new ValueMetaInternetAddress( "FOO" ), "", "", false, false, false ) );
assertEquals( " UNKNOWN" + System.getProperty( "line.separator" ),
odbcMeta.getFieldDefinition( new ValueMetaInternetAddress( "FOO" ), "", "", false, false, true ) );
}
private int rowCnt = 0;
@Test
public void testCheckIndexExists() throws Exception {
Database db = Mockito.mock( Database.class );
ResultSet rs = Mockito.mock( ResultSet.class );
DatabaseMetaData dmd = Mockito.mock( DatabaseMetaData.class );
DatabaseMeta dm = Mockito.mock( DatabaseMeta.class );
Mockito.when( dm.getQuotedSchemaTableCombination( "", "FOO" ) ).thenReturn( "FOO" );
Mockito.when( rs.next() ).thenAnswer( new Answer<Boolean>() {
public Boolean answer( InvocationOnMock invocation ) throws Throwable {
rowCnt++;
return new Boolean( rowCnt < 3 );
}
} );
Mockito.when( db.getDatabaseMetaData() ).thenReturn( dmd );
Mockito.when( dmd.getIndexInfo( null, null, "FOO", false, true ) ).thenReturn( rs );
Mockito.when( rs.getString( "COLUMN_NAME" ) ).thenAnswer( new Answer<String>() {
@Override
public String answer( InvocationOnMock invocation ) throws Throwable {
if ( rowCnt == 1 ) {
return "ROW1COL2";
} else if ( rowCnt == 2 ) {
return "ROW2COL2";
} else {
return null;
}
}
} );
Mockito.when( db.getDatabaseMeta() ).thenReturn( dm );
assertTrue( odbcMeta.checkIndexExists( db, "", "FOO", new String[] { "ROW1COL2", "ROW2COL2" } ) );
assertFalse( odbcMeta.checkIndexExists( db, "", "FOO", new String[] { "ROW2COL2", "NOTTHERE" } ) );
assertFalse( odbcMeta.checkIndexExists( db, "", "FOO", new String[] { "NOTTHERE", "ROW1COL2" } ) );
}
}