You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by rh...@apache.org on 2014/03/29 18:32:18 UTC

svn commit: r1583032 - in /db/derby/code/trunk: ./ java/engine/ java/engine/org/apache/derby/impl/optional/lucene/ java/engine/org/apache/derby/optional/ java/testing/org/apache/derbyTesting/functionTests/tests/lang/

Author: rhillegas
Date: Sat Mar 29 17:32:18 2014
New Revision: 1583032

URL: http://svn.apache.org/r1583032
Log:
DERBY-590: Make the Lucene plugin locale-sensitive; commit derby-590-09-aa-localeSensitiveAnalysis.diff.

Added:
    db/derby/code/trunk/java/engine/org/apache/derby/optional/
    db/derby/code/trunk/java/engine/org/apache/derby/optional/LuceneUtils.java   (with props)
    db/derby/code/trunk/java/engine/org/apache/derby/optional/build.xml   (with props)
Modified:
    db/derby/code/trunk/build.xml
    db/derby/code/trunk/java/engine/build.xml
    db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneListIndexesVTI.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneQueryVTI.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneSupport.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/build.xml
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneCollationTest.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneSupportPermsTest.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneSupportTest.java

Modified: db/derby/code/trunk/build.xml
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/build.xml?rev=1583032&r1=1583031&r2=1583032&view=diff
==============================================================================
--- db/derby/code/trunk/build.xml (original)
+++ db/derby/code/trunk/build.xml Sat Mar 29 17:32:18 2014
@@ -1072,7 +1072,7 @@
 
     <javadoc sourcepath="${out.javadoc.dir}/sourcedir"
              bootclasspath="${bootClasspath}"
-             classpath="${bootClasspath};${osgi};${servlet24};${out.dir}"
+             classpath="${bootClasspath};${osgi};${servlet24};${out.dir};${jars.javadoc}"
              breakiterator="true"
              destdir="${public.api.dir}"
     	     Overview="${basedir}/published_api_overview.html"

Modified: db/derby/code/trunk/java/engine/build.xml
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/build.xml?rev=1583032&r1=1583031&r2=1583032&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/build.xml (original)
+++ db/derby/code/trunk/java/engine/build.xml Sat Mar 29 17:32:18 2014
@@ -66,6 +66,7 @@
     <ant dir="${derby.engine.dir}/jdbc"/>
     <ant dir="${derby.engine.dir}/osgi"/>
     <ant dir="${derby.engine.dir}/catalog"/>   
+    <ant dir="${derby.engine.dir}/optional"/>
     <ant dir="${derby.engine.dir}/diag"/>
       	<copy todir="${out.dir}/${derby.dir}">
           <fileset dir="${derby.engine.dir}">

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneListIndexesVTI.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneListIndexesVTI.java?rev=1583032&r1=1583031&r2=1583032&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneListIndexesVTI.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneListIndexesVTI.java Sat Mar 29 17:32:18 2014
@@ -25,9 +25,12 @@ import java.io.File;
 import java.io.FileFilter;
 import java.io.IOException;
 import java.security.PrivilegedActionException;
+import java.sql.Connection;
 import java.sql.SQLException;
+import java.sql.Timestamp;
 import java.text.DateFormat;
 import java.util.ArrayList;
+import java.util.Properties;
 
 import org.apache.derby.shared.common.reference.SQLState;
 import org.apache.derby.vti.StringColumnVTI;
@@ -37,12 +40,17 @@ import org.apache.derby.vti.StringColumn
  * See org.apache.derby.impl.optional.lucene.LuceneSupport.listIndexes.
  * 
  */
-public class LuceneListIndexesVTI extends StringColumnVTI {
-	
-	File[] indexes;
-	int row = -1;
-	String schema, table;
-	
+public class LuceneListIndexesVTI extends StringColumnVTI
+{
+    private Connection  connection;
+	private File[] indexes;
+	private int row = -1;
+
+    private String      schema;
+    private String      table;
+    private String      column;
+    private Properties  rowProperties;
+
 	/**
 	 * Return a new LuceneListIndexesVTI.
 	 * 
@@ -51,9 +59,21 @@ public class LuceneListIndexesVTI extend
 	public LuceneListIndexesVTI()
         throws IOException, PrivilegedActionException, SQLException
     {
-		super( new String[] { "SCHEMANAME","TABLENAME","COLUMNNAME","LASTUPDATED" } );
+		super
+            ( new String[]
+                {
+                    "SCHEMANAME",
+                    "TABLENAME",
+                    "COLUMNNAME",
+                    "LASTUPDATED",
+                    "LUCENEVERSION",
+                    "ANALYZER",
+                    "ANALYZERMAKER",
+                }
+              );
 		
-		String dir = LuceneSupport.getIndexLocation( LuceneSupport.getDefaultConnection(), null, null, null );
+        connection = LuceneSupport.getDefaultConnection();
+		String dir = LuceneSupport.getIndexLocation( connection, null, null, null );
 		
 		File luceneDir = new File(dir);
         DirFilter   dirFilter = new DirFilter();
@@ -80,11 +100,23 @@ public class LuceneListIndexesVTI extend
         allIndexes.toArray( indexes );
 	}
 
-	public void close() throws SQLException {
-		
+	public void close() throws SQLException
+    {
+		connection = null;
+        indexes = null;
+        schema = null;
+        table = null;
+        column = null;
+        rowProperties = null;
 	}
 
-	public boolean next() throws SQLException {
+	public boolean next() throws SQLException
+    {
+        schema = null;
+        table = null;
+        column = null;
+        rowProperties = null;
+        
 		row++;
 		if (row < indexes.length) {
 			return true;
@@ -100,29 +132,39 @@ public class LuceneListIndexesVTI extend
 	 * 4 == column name
 	 * 5 == last modified
 	 */
-	protected String getRawColumn(int col) throws SQLException {
-
-        File    columnDir = indexes[ row ];
-        String columnPart = columnDir.getName();
-        File    tableDir = columnDir.getParentFile();
-        String  tablePart = tableDir.getName();
-        File    schemaDir = tableDir.getParentFile();
-        String  schemaPart = schemaDir.getName();
-
-		if (col == 1) {
-			return schemaPart;
-		} else if (col == 2) {
-			return tablePart;
-		} else if (col == 3) {
-			return columnPart;
-		} else if (col == 4) {
+	protected String getRawColumn( int col ) throws SQLException
+    {
+        readSchemaTableColumn();
+        
+        switch( col )
+        {
+        case 1: return schema;
+        case 2: return table;
+        case 3: return column;
+        case 5: return getProperty( LuceneSupport.LUCENE_VERSION );
+        case 6: return getProperty( LuceneSupport.ANALYZER );
+        case 7: return getProperty( LuceneSupport.ANALYZER_MAKER );
+        default:
+            throw LuceneSupport.newSQLException
+                (
+                 SQLState.LANG_INVALID_COLUMN_POSITION,
+                 new Integer( col ),
+                 new Integer( getColumnCount() )
+                 );
+        }
+            /*
             try {
                 DateFormat df = DateFormat.getDateTimeInstance();
                 return df.format( LuceneSupport.getLastModified( columnDir ) );
             }
             catch (Exception e) { throw LuceneSupport.wrap( e ); }
-		}
-        else
+            */
+	}
+
+    /** Get the timestamp value of the 1-based column id */
+    public  Timestamp   getTimestamp( int col ) throws SQLException
+    {
+        if ( col != 4 )
         {
             throw LuceneSupport.newSQLException
                 (
@@ -130,12 +172,59 @@ public class LuceneListIndexesVTI extend
                  new Integer( col ),
                  new Integer( getColumnCount() )
                  );
-            }
-	}
+        }
+
+        try {
+            long    timestampMillis = Long.parseLong( getProperty( LuceneSupport.UPDATE_TIMESTAMP ) );
+
+            return new Timestamp( timestampMillis );
+        }
+        catch (NumberFormatException nfe) { throw LuceneSupport.wrap( nfe ); }
+    }
+    
 	
     public  static  class   DirFilter   implements  FileFilter
     {
         public  boolean accept( File file ) { return file.isDirectory(); }
     }
 
+    /** Fill in the schema, table, and column names */
+    private void    readSchemaTableColumn()
+        throws SQLException
+    {
+        if ( column != null ) { return; }
+        
+        File    columnDir = indexes[ row ];
+        column = columnDir.getName();
+        File    tableDir = columnDir.getParentFile();
+        table = tableDir.getName();
+        File    schemaDir = tableDir.getParentFile();
+        schema = schemaDir.getName();
+    }
+
+    /** get the string value of a property from the row properties */
+    private String  getProperty( String key )
+        throws SQLException
+    {
+        return getRowProperties().getProperty( key );
+    }
+    
+    /** get the properties of the current row */
+    private Properties  getRowProperties()
+        throws SQLException
+    {
+        if ( rowProperties == null )
+        {
+            try {
+                readSchemaTableColumn();
+                File    indexPropertiesFile = LuceneSupport.getIndexPropertiesFile( connection, schema, table, column );
+                rowProperties = LuceneSupport.readIndexProperties( indexPropertiesFile );
+            }
+            catch (IOException ioe) { throw LuceneSupport.wrap( ioe ); }
+            catch (PrivilegedActionException pae) { throw LuceneSupport.wrap( pae ); }
+        }
+
+        return rowProperties;
+    }
+
 }
\ No newline at end of file

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneQueryVTI.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneQueryVTI.java?rev=1583032&r1=1583031&r2=1583032&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneQueryVTI.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneQueryVTI.java Sat Mar 29 17:32:18 2014
@@ -23,6 +23,7 @@ package org.apache.derby.impl.optional.l
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
 import java.security.PrivilegedActionException;
 import java.sql.Connection;
 import java.sql.Date;
@@ -30,8 +31,10 @@ import java.sql.DriverManager;
 import java.sql.SQLException;
 import java.sql.Time;
 import java.sql.Timestamp;
+import java.util.Properties;
 
 import org.apache.derby.shared.common.reference.SQLState;
+import org.apache.derby.optional.LuceneUtils;
 import org.apache.derby.vti.RestrictedVTI;
 import org.apache.derby.vti.Restriction;
 import org.apache.derby.vti.Restriction.ColumnQualifier;
@@ -417,12 +420,16 @@ public class LuceneQueryVTI extends Stri
             // make sure the user has SELECT privilege on all relevant columns of the underlying table
             vetPrivileges();
         
-            String indexhome = LuceneSupport.getIndexLocation( _connection, _schema, _table, _column);
+            String          indexhome = LuceneSupport.getIndexLocation( _connection, _schema, _table, _column);
+            File            propertiesFile = LuceneSupport.getIndexPropertiesFile( _connection, _schema, _table, _column );
+            Properties  indexProperties = LuceneSupport.readIndexProperties( propertiesFile );
+            String          analyzerMaker = indexProperties.getProperty( LuceneSupport.ANALYZER_MAKER );
+            Analyzer    analyzer = LuceneSupport.getAnalyzer( analyzerMaker );
 				
             _indexReader = LuceneSupport.getIndexReader( new File( indexhome.toString() ) );
             _searcher = new IndexSearcher(_indexReader);
-            Analyzer analyzer = new StandardAnalyzer( Version.LUCENE_45 );
-            QueryParser qp = new QueryParser( Version.LUCENE_45, TEXT_FIELD_NAME, analyzer );
+
+            QueryParser qp = new QueryParser( LuceneUtils.currentVersion(), TEXT_FIELD_NAME, analyzer );
             Query luceneQuery = qp.parse( _queryText );
             TopScoreDocCollector tsdc = TopScoreDocCollector.create(1000, true);
             if ( _rankCutoff != 0 ) {
@@ -435,6 +442,10 @@ public class LuceneQueryVTI extends Stri
         catch (IOException ioe) { throw LuceneSupport.wrap( ioe ); }
         catch (ParseException pe) { throw LuceneSupport.wrap( pe ); }
         catch (PrivilegedActionException pae) { throw LuceneSupport.wrap( pae ); }
+        catch (ClassNotFoundException cnfe) { throw LuceneSupport.wrap( cnfe ); }
+        catch (IllegalAccessException iae) { throw LuceneSupport.wrap( iae ); }
+        catch (InvocationTargetException ite) { throw LuceneSupport.wrap( ite ); }
+        catch (NoSuchMethodException nsme) { throw LuceneSupport.wrap( nsme ); }
     }
 
     /**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneSupport.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneSupport.java?rev=1583032&r1=1583031&r2=1583032&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneSupport.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/LuceneSupport.java Sat Mar 29 17:32:18 2014
@@ -23,7 +23,11 @@ package org.apache.derby.impl.optional.l
 
 import java.io.File;
 import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.nio.charset.Charset;
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
@@ -41,12 +45,14 @@ import java.sql.Timestamp;
 import java.sql.Types;
 import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Properties;
 
 import org.apache.derby.iapi.sql.dictionary.OptionalTool;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.util.IdUtil;
 import org.apache.derby.impl.jdbc.EmbedConnection;
 import org.apache.derby.shared.common.reference.SQLState;
+import org.apache.derby.optional.LuceneUtils;
 import org.apache.derby.vti.Restriction.ColumnQualifier;
 import org.apache.derby.vti.VTITemplate;
 
@@ -91,6 +97,23 @@ public class LuceneSupport implements Op
     static  final   int TABLE_PART = 0;
     static  final   int COLUMN_PART = TABLE_PART + 1;
     static  final   int PART_COUNT = COLUMN_PART + 1;
+
+    // file which holds properties specific to a Lucene index
+    private static  final   String  PROPERTIES_FILE_NAME = "derby-lucene.properties";
+
+    // properties which go in that file
+
+    /** property identifying the static method which materializes an Analyzer for the index */
+    public  static  final   String  ANALYZER_MAKER = "derby.lucene.analyzer.maker";
+
+    /** class name of the Analyzer used for the index */
+    public  static  final   String  ANALYZER = "derby.lucene.analyzer";
+
+    /** version of Lucene used to create or recreate an index */
+    public  static  final   String  LUCENE_VERSION = "derby.lucene.version";
+	
+    /** system time when the index was created/updated */
+    public  static  final   String  UPDATE_TIMESTAMP = "derby.lucene.last.updated";
 	
     /////////////////////////////////////////////////////////////////////
     //
@@ -130,7 +153,10 @@ public class LuceneSupport implements Op
 		listFunction.append("schemaname varchar( 128 ),");
 		listFunction.append("tablename varchar( 128 ),");
 		listFunction.append("columnname varchar( 128 ),");
-		listFunction.append("lastupdated timestamp");
+		listFunction.append("lastupdated timestamp,");
+		listFunction.append("luceneversion varchar( 20 ),");
+		listFunction.append("analyzer varchar( 32672 ),");
+		listFunction.append("analyzermaker varchar( 32672 )");
 		listFunction.append(")");
 		listFunction.append("language java ");
 		listFunction.append("parameter style DERBY_JDBC_RESULT_SET ");
@@ -143,7 +169,8 @@ public class LuceneSupport implements Op
 		createProcedure.append("create procedure " + CREATE_INDEX );
 		createProcedure.append(" (schemaname varchar( 128 ),");
 		createProcedure.append("tablename varchar( 128 ),");
-		createProcedure.append("textcolumn varchar( 128 ))");
+		createProcedure.append("textcolumn varchar( 128 ),");
+		createProcedure.append("analyzerMaker varchar( 32672 ))");
 		createProcedure.append("parameter style java modifies sql data language java external name ");
 		createProcedure.append("'" + getClass().getName() + ".createIndex'");
 		
@@ -163,7 +190,8 @@ public class LuceneSupport implements Op
 		updateProcedure.append("create procedure " + UPDATE_INDEX );
 		updateProcedure.append(" (schemaname varchar( 128 ),");
 		updateProcedure.append("tablename varchar( 128 ),");
-		updateProcedure.append("textcolumn varchar( 128 ))");
+		updateProcedure.append("textcolumn varchar( 128 ),");
+		updateProcedure.append("analyzerMaker varchar( 32672 ))");
 		updateProcedure.append("parameter style java reads sql data language java external name ");
 		updateProcedure.append("'" + getClass().getName() + ".updateIndex'");
 		
@@ -300,11 +328,13 @@ public class LuceneSupport implements Op
 	 * @param schema Schema where the indexed column resides
 	 * @param table table where the indexed column resides
 	 * @param textcol the indexed column
+	 * @param analyzerMaker name of static method which instantiates an Analyzer. may be null.
 	 * @throws SQLException
 	 * @throws IOException
 	 */
-	public static void updateIndex( String schema, String table, String textcol )
-        throws SQLException, IOException, PrivilegedActionException
+	public static void updateIndex( String schema, String table, String textcol, String analyzerMaker )
+        throws SQLException, IOException, PrivilegedActionException,
+               ClassNotFoundException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
     {
         Connection              conn = getDefaultConnection();
 
@@ -316,7 +346,7 @@ public class LuceneSupport implements Op
             throw newSQLException( SQLState.LUCENE_INDEX_DOES_NOT_EXIST );
         }
 
-        createOrRecreateIndex( conn, schema, table, textcol, false );
+        createOrRecreateIndex( conn, schema, table, textcol, analyzerMaker, false );
 	}
 	
     /////////////////////////////////////////////////////////////////////
@@ -331,11 +361,13 @@ public class LuceneSupport implements Op
 	 * @param schema The schema of the column to index
 	 * @param table The table of the column to index
 	 * @param textcol The column to create the Lucene index on
+	 * @param analyzerMaker name of static method which instantiates an Analyzer. may be null.
 	 * @throws SQLException
 	 * @throws IOException
 	 */
-	public static void createIndex( String schema, String table, String textcol )
-        throws SQLException, IOException, PrivilegedActionException
+	public static void createIndex( String schema, String table, String textcol, String analyzerMaker )
+        throws SQLException, IOException, PrivilegedActionException,
+               ClassNotFoundException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
     {
         Connection              conn = getDefaultConnection();
         DatabaseMetaData    dbmd = conn.getMetaData();
@@ -343,7 +375,7 @@ public class LuceneSupport implements Op
         // First make sure that the text column exists and is a String type
         vetTextColumn( dbmd, schema, table, textcol );
 
-        createOrRecreateIndex( conn, schema, table, textcol, true );
+        createOrRecreateIndex( conn, schema, table, textcol, analyzerMaker, true );
 	}
 
 	/**
@@ -352,6 +384,7 @@ public class LuceneSupport implements Op
 	 * @param schema The schema of the column to index
 	 * @param table The table of the column to index
 	 * @param textcol The column to create the Lucene index on
+	 * @param analyzerMaker name of static method which instantiates an Analyzer. may be null.
 	 * @param create True if the index is to be created, false if it is to be recreated
 	 * @throws SQLException
 	 * @throws IOException
@@ -362,9 +395,11 @@ public class LuceneSupport implements Op
          String schema,
          String table,
          String textcol,
+         String analyzerMaker,
          boolean create
          )
-        throws SQLException, IOException, PrivilegedActionException
+        throws SQLException, IOException, PrivilegedActionException,
+               ClassNotFoundException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
     {
         VTITemplate.ColumnDescriptor[] primaryKeys = getPrimaryKeys( conn, schema, table );
         if ( primaryKeys.length == 0 )
@@ -373,11 +408,28 @@ public class LuceneSupport implements Op
         }
         int             keyCount = 0;
 
+        File            propertiesFile = getIndexPropertiesFile( conn, schema, table, textcol );
+
         //
         // Drop the old index directory if we're recreating the index.
         // We do this after verifying that the key exists.
         //
-        if ( !create ) { dropIndexDirectories( schema, table, textcol ); }
+        if ( !create )
+        {
+            dropIndexDirectories( schema, table, textcol );
+        }
+
+        Version luceneVersion = LuceneUtils.currentVersion();
+
+        // get the Analyzer. use the default if the user didn't specify an override
+        if ( analyzerMaker == null ) { analyzerMaker = LuceneUtils.class.getName() + ".defaultAnalyzer"; }
+        Analyzer    analyzer = getAnalyzer( analyzerMaker );
+
+        Properties  indexProperties = new Properties();
+        indexProperties.setProperty( LUCENE_VERSION, luceneVersion.toString() );
+        indexProperties.setProperty( UPDATE_TIMESTAMP, Long.toString( System.currentTimeMillis() ) );
+        indexProperties.setProperty( ANALYZER_MAKER, analyzerMaker );
+        indexProperties.setProperty( ANALYZER, analyzer.getClass().getName() );
             
         StringBuilder   tableFunction = new StringBuilder();
         tableFunction.append( "create function " + makeTableFunctionName( schema, table, textcol ) + "\n" );
@@ -388,7 +440,7 @@ public class LuceneSupport implements Op
         ResultSet rs = null;
         IndexWriter iw = null;
         try {
-            iw = getIndexWriter( schema, table, textcol );
+            iw = getIndexWriter( luceneVersion, analyzer, schema, table, textcol );
 
             // select all keys and the textcol from this column, add to lucene index
             StringBuilder query = new StringBuilder("select ");
@@ -439,6 +491,8 @@ public class LuceneSupport implements Op
                     doc.add(new TextField( LuceneQueryVTI.TEXT_FIELD_NAME, textcolValue, Store.NO));
                 }
                 addDocument( iw, doc );
+
+                writeIndexProperties( propertiesFile, indexProperties );
             }
         }
         finally
@@ -969,6 +1023,76 @@ public class LuceneSupport implements Op
 
     /////////////////////////////////////////////////////////////////////
     //
+    //  MANAGE THE INDEX PROPERTIES FILE
+    //
+    /////////////////////////////////////////////////////////////////////
+
+    /**
+     * <p>
+     * Get the handle on the file holding the index properties.
+     * </p>
+     */
+	static File getIndexPropertiesFile( Connection conn, String schema, String table, String textcol )
+        throws SQLException, IOException, PrivilegedActionException
+    {
+		File indexDir = new File( getIndexLocation( conn, schema, table, textcol ) );
+        File    propertiesFile = new File( indexDir, PROPERTIES_FILE_NAME );
+
+        return propertiesFile;
+    }
+    
+    /** Read the index properties file */
+    static  Properties readIndexProperties( final File file )
+        throws IOException, PrivilegedActionException
+    {
+        return AccessController.doPrivileged
+            (
+             new PrivilegedExceptionAction<Properties>()
+             {
+                public Properties run() throws IOException
+                {
+                    if ( file == null ) { return null; }
+                    else
+                    {
+                        Properties  properties = new Properties();
+
+                        properties.load( new FileInputStream( file ) );
+                        
+                        return properties;
+                    }
+                }
+             }
+             );
+    }
+
+    /** Write the index properties file */
+    private static  void    writeIndexProperties( final File file, final Properties properties )
+        throws IOException, PrivilegedActionException
+    {
+        AccessController.doPrivileged
+            (
+             new PrivilegedExceptionAction<Object>()
+             {
+                public Object run() throws IOException
+                {
+                    if ( (file == null) || (properties == null) ) { return null; }
+                    else
+                    {
+                        FileOutputStream    fos = new FileOutputStream( file );
+
+                        properties.store( fos, null );
+                        fos.flush();
+                        fos.close();
+
+                        return null;
+                    }
+                }
+             }
+             );
+    }
+
+    /////////////////////////////////////////////////////////////////////
+    //
     //  SQL/JDBC SUPPORT
     //
     /////////////////////////////////////////////////////////////////////
@@ -1309,6 +1433,23 @@ public class LuceneSupport implements Op
              );
     }
 
+    /** Return true if the file exists */
+    static  boolean fileExists( final File file )
+        throws IOException, PrivilegedActionException
+    {
+        return AccessController.doPrivileged
+            (
+             new PrivilegedExceptionAction<Boolean>()
+             {
+                public Boolean run() throws IOException
+                {
+                    if ( file == null ) { return false; }
+                    else { return file.exists(); }
+                }
+             }
+             ).booleanValue();
+    }
+
 	/**
 	 * Get the system property derby.system.home using the security manager.
 	 * @return Returns the value of the system property derby.system.home, or user.dir if not set.
@@ -1383,6 +1524,8 @@ public class LuceneSupport implements Op
 	 * Returns a Lucene IndexWriter, that writes inside the lucene directory inside the database
 	 * directory.
 	 * 
+	 * @param luceneVersion the version of Lucene being used
+	 * @param analyzer      the Analyzer being used
 	 * @param schema The schema of the indexed column
 	 * @param table The table of the indexed column
 	 * @param textcol The name of the column to be indexed
@@ -1390,6 +1533,8 @@ public class LuceneSupport implements Op
 	 */
 	private static IndexWriter getIndexWriter
         (
+         final Version  luceneVersion,
+         final  Analyzer    analyzer,
          final String schema,
          final String table,
          final String textcol
@@ -1405,10 +1550,8 @@ public class LuceneSupport implements Op
                      Directory dir = FSDirectory.open(new File( getIndexLocation( getDefaultConnection(), schema, table, textcol ) ) );
 
                      // allow this to be overridden in the configuration during load later.
-                     Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_45);
-                     IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_45,
-                                                                   analyzer);
-                     IndexWriter iw = new IndexWriter(dir, iwc);
+                     IndexWriterConfig iwc = new IndexWriterConfig( luceneVersion, analyzer );
+                     IndexWriter iw = new IndexWriter( dir, iwc );
 		
                      return iw;
                  }
@@ -1480,4 +1623,30 @@ public class LuceneSupport implements Op
              );
 	}
 	
+	/**
+	 * Invoke a static method (possibly supplied by the user) to instantiate an Analyzer.
+     * The method has no arguments.
+	 */
+	static Analyzer getAnalyzer( final String analyzerMaker )
+        throws ClassNotFoundException, IllegalAccessException, InvocationTargetException,
+               NoSuchMethodException, PrivilegedActionException
+    {
+        return AccessController.doPrivileged
+            (
+             new PrivilegedExceptionAction<Analyzer>()
+             {
+                 public Analyzer run()
+                     throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
+                 {
+                     int    lastDotIdx = analyzerMaker.lastIndexOf( "." );
+                     Class<? extends Object>  klass = Class.forName( analyzerMaker.substring( 0, lastDotIdx ) );
+                     String methodName = analyzerMaker.substring( lastDotIdx + 1, analyzerMaker.length() );
+                     Method method = klass.getDeclaredMethod( methodName );
+                     
+                     return (Analyzer) method.invoke( null );
+                 }
+             }
+             );
+	}
+	
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/build.xml
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/build.xml?rev=1583032&r1=1583031&r2=1583032&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/build.xml (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/optional/lucene/build.xml Sat Mar 29 17:32:18 2014
@@ -56,6 +56,7 @@
         <pathelement path="${lucene_qp}"/>
       </classpath>
       <include name="${derby.dir}/${cur.dir}/**"/>
+      <compilerarg value="-Xlint:unchecked"/>
     </javac>
    </target>
 </project>

Added: db/derby/code/trunk/java/engine/org/apache/derby/optional/LuceneUtils.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/optional/LuceneUtils.java?rev=1583032&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/optional/LuceneUtils.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/optional/LuceneUtils.java Sat Mar 29 17:32:18 2014
@@ -0,0 +1,191 @@
+/*
+
+   Derby - Class org.apache.derby.optional.LuceneUtils
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.apache.derby.optional;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Locale;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.util.Version;
+
+import org.apache.derby.iapi.sql.conn.ConnectionUtil;
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
+
+/**
+ * <p>
+ * Utility methods for the Lucene optional tool.
+ * </p>
+ */
+public abstract class LuceneUtils
+{
+    /////////////////////////////////////////////////////////////////
+    //
+    //  CONSTANTS
+    //
+    /////////////////////////////////////////////////////////////////
+
+    /////////////////////////////////////////////////////////////////
+    //
+    //  STATE
+    //
+    /////////////////////////////////////////////////////////////////
+
+    /** Map of Analyzers keyed by language code */
+    private static  HashMap<String,Class<? extends Analyzer>>   _analyzerClasses;
+    static
+    {
+        _analyzerClasses = new HashMap<String,Class<? extends Analyzer>>();
+
+        storeAnalyzerClass( org.apache.lucene.analysis.ar.ArabicAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.hy.ArmenianAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.eu.BasqueAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.br.BrazilianAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.bg.BulgarianAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.ca.CatalanAnalyzer.class );
+        // deprecated, use StandardAnalyzer instead: storeAnalyzerClass( org.apache.lucene.analysis.cn.ChineseAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.cz.CzechAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.da.DanishAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.nl.DutchAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.en.EnglishAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.fi.FinnishAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.fr.FrenchAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.gl.GalicianAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.de.GermanAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.el.GreekAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.hi.HindiAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.hu.HungarianAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.id.IndonesianAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.ga.IrishAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.it.ItalianAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.lv.LatvianAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.no.NorwegianAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.fa.PersianAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.pt.PortugueseAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.ro.RomanianAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.ru.RussianAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.es.SpanishAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.sv.SwedishAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.th.ThaiAnalyzer.class );
+        storeAnalyzerClass( org.apache.lucene.analysis.tr.TurkishAnalyzer.class );
+    }
+
+    /////////////////////////////////////////////////////////////////
+    //
+    //  PUBLIC BEHAVIOR
+    //
+    /////////////////////////////////////////////////////////////////
+
+    /** Get the version of the Lucene library on the classpath. */
+    @SuppressWarnings("deprecation")
+    public  static  Version currentVersion()
+    {
+        Version retval = null;
+
+        // the current version is the highest one
+        for ( Version current : Version.values() )
+        {
+            if ( current == Version.LUCENE_CURRENT ) { continue; }
+            
+            if ( retval == null ) { retval = current; }
+            else
+            {
+                if ( current.onOrAfter( retval ) ) { retval = current; }
+            }
+        }
+        
+        return retval;
+    }
+
+    /**
+     * <p>
+     * Get the default Analyzer associated with the database Locale.
+     * </p>
+     */
+    public  static  Analyzer    defaultAnalyzer()
+        throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, SQLException
+    {
+        return getAnalyzerForLocale( ConnectionUtil.getCurrentLCC().getDatabase().getLocale() );
+    }
+    
+    /**
+     * <p>
+     * Get the Analyzer associated with the given Locale.
+     * </p>
+     */
+    public  static  Analyzer    getAnalyzerForLocale( Locale locale )
+        throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException
+    {
+        String          language = locale.getLanguage();
+
+        Class<? extends Analyzer>   analyzerClass = _analyzerClasses.get( language );
+        
+        if ( analyzerClass == null )    { return standardAnalyzer(); }
+        else
+        {
+            Constructor<? extends Analyzer> constructor = analyzerClass.getConstructor( Version.class );
+
+            return constructor.newInstance( currentVersion() );
+        }
+    }
+
+    /**
+     * <p>
+     * Get the StandardAnalyzer for parsing text.
+     * </p>
+     */
+    public  static  Analyzer    standardAnalyzer()
+    {
+        return new StandardAnalyzer( currentVersion() );
+    }
+    
+    /////////////////////////////////////////////////////////////////
+    //
+    //  MINIONS
+    //
+    /////////////////////////////////////////////////////////////////
+
+    /** Store an Analyzer class in the HashMap of Analyzers, keyed by language code */
+    private static  void    storeAnalyzerClass( Class<? extends Analyzer> analyzerClass )
+    {
+        _analyzerClasses.put( getLanguageCode( analyzerClass ), analyzerClass );
+    }
+
+    /**
+     * <p>
+     * Get the language code for a Lucene Analyzer. Each of the Analyzers
+     * lives in a package whose last leg is the language code.
+     * </p>
+     */
+    private static  String  getLanguageCode( Class<? extends Analyzer> analyzerClass )
+    {
+        String  className = analyzerClass.getName();
+        String  packageName = className.substring( 0, className.lastIndexOf( "." ) );
+        String  languageCode = packageName.substring( packageName.lastIndexOf( "." ) + 1, packageName.length() );
+
+        return languageCode;
+    }
+
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/optional/LuceneUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/engine/org/apache/derby/optional/build.xml
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/optional/build.xml?rev=1583032&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/optional/build.xml (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/optional/build.xml Sat Mar 29 17:32:18 2014
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to you 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.
+-->
+
+<project default="optional" basedir="../../../../../..">
+
+<!-- Set Properties -->
+  <!-- User settings -->
+  <property file="${user.home}/ant.properties"/>
+  <!-- Set property lib dir -->
+  <property name="properties.dir" value="tools/ant/properties"/>
+  <!-- Significant dirs -->
+  <property file="${properties.dir}/dirs.properties"/>
+  <!-- Compiler settings -->
+<property file="${properties.dir}/defaultcompiler.properties"/> 
+  <property file="${properties.dir}/${build.compiler}.properties"/>
+  <!-- Compile-time classpath properties files -->
+  <property file="${properties.dir}/extrapath.properties"/>
+  <property file="${properties.dir}/compilepath.properties"/>
+  <property name="cur.dir" value="optional"/>
+
+<!-- Targets -->
+
+   <target name="optional">
+    <javac
+      source="1.6"
+      target="1.6"
+      bootclasspath="${empty}"
+      nowarn="on"
+      debug="${debug}"
+      depend="${depend}"
+      deprecation="${deprecation}"
+      optimize="${optimize}"
+      proceed="${proceed}"
+      verbose="${verbose}"
+      srcdir="${derby.engine.src.dir}:${generated.src.dir}"
+      destdir="${out.dir}">
+      <classpath>
+        <pathelement path="${java16compile.classpath}"/>
+        <pathelement path="${lucene_core}"/>
+        <pathelement path="${lucene_a_co}"/>
+        <pathelement path="${lucene_qp}"/>
+      </classpath>
+      <include name="${derby.dir}/${cur.dir}/**"/>
+      <compilerarg value="-Xlint:unchecked"/>
+    </javac>
+   </target>
+</project>
+

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/optional/build.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneCollationTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneCollationTest.java?rev=1583032&r1=1583031&r2=1583032&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneCollationTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneCollationTest.java Sat Mar 29 17:32:18 2014
@@ -53,8 +53,8 @@ public class LuceneCollationTest extends
 
     private static  final   String      LOAD_TOOL = "call syscs_util.syscs_register_tool( 'luceneSupport', true )";
     private static  final   String      UNLOAD_TOOL = "call syscs_util.syscs_register_tool( 'luceneSupport', false )";
-    private static  final   String      INDEX_POEMS = "call LuceneSupport.createIndex( 'ruth', 'poems', 'poemText' )";
-    private static  final   String      UPDATE_POEMS_INDEX = "call LuceneSupport.updateIndex( 'ruth', 'poems', 'poemText' )";
+    private static  final   String      INDEX_POEMS = "call LuceneSupport.createIndex( 'ruth', 'poems', 'poemText', null )";
+    private static  final   String      UPDATE_POEMS_INDEX = "call LuceneSupport.updateIndex( 'ruth', 'poems', 'poemText', null )";
     private static  final   String      DROP_POEMS_INDEX = "call LuceneSupport.dropIndex( 'ruth', 'poems', 'poemText' )";
 
     ///////////////////////////////////////////////////////////////////////////////////
@@ -150,11 +150,12 @@ public class LuceneCollationTest extends
         assertResults
             (
              conn,
-             "select * from table ( ruth.poems__poemText( 'star', 0 ) ) luceneResults",
+             "select * from table ( ruth.poems__poemText( 'star', 0 ) ) luceneResults order by poemID",
              new String[][]
              {
-                 { "5", "5", "4", "0.3304931" },
-                 { "3", "3", "2", "0.2832798" },
+                 { "3", "3", "2", "0.22933942" },
+                 { "4", "4", "3", "0.22933942" },
+                 { "5", "5", "4", "0.26756266" },
              },
              false
              );

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneSupportPermsTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneSupportPermsTest.java?rev=1583032&r1=1583031&r2=1583032&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneSupportPermsTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneSupportPermsTest.java Sat Mar 29 17:32:18 2014
@@ -39,11 +39,14 @@ import java.sql.Timestamp;
 import java.sql.Types;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Locale;
 import junit.framework.Test;
 import junit.framework.TestSuite;
+import org.apache.derby.iapi.sql.conn.ConnectionUtil;
 import org.apache.derbyTesting.junit.BaseJDBCTestCase;
 import org.apache.derbyTesting.junit.JDBC;
 import org.apache.derbyTesting.junit.DatabasePropertyTestSetup;
+import org.apache.derbyTesting.junit.LocaleTestSetup;
 import org.apache.derbyTesting.junit.SecurityManagerSetup;
 import org.apache.derbyTesting.junit.TestConfiguration;
 import org.apache.derbyTesting.junit.CleanDatabaseTestSetup;
@@ -85,13 +88,17 @@ public class LuceneSupportPermsTest exte
 
     private static  final   String      LOAD_TOOL = "call syscs_util.syscs_register_tool( 'luceneSupport', true )";
     private static  final   String      UNLOAD_TOOL = "call syscs_util.syscs_register_tool( 'luceneSupport', false )";
-    private static  final   String      INDEX_POEMS = "call LuceneSupport.createIndex( 'ruth', 'poems', 'poemText' )";
-    private static  final   String      UPDATE_POEMS_INDEX = "call LuceneSupport.updateIndex( 'ruth', 'poems', 'poemText' )";
+    private static  final   String      INDEX_POEMS = "call LuceneSupport.createIndex( 'ruth', 'poems', 'poemText', null )";
+    private static  final   String      UPDATE_POEMS_INDEX = "call LuceneSupport.updateIndex( 'ruth', 'poems', 'poemText', null )";
     private static  final   String      DROP_POEMS_INDEX = "call LuceneSupport.dropIndex( 'ruth', 'poems', 'poemText' )";
 
     private static  final   long        MILLIS_IN_HOUR = 1000L * 60L * 60L;
     private static  final   long        MILLIS_IN_DAY = MILLIS_IN_HOUR * 24L;
 
+    private static  final   String      LUCENE_VERSION = "LUCENE_45";
+    private static  final   String      LANGUAGE = "en";
+    private static  final   String      COUNTRY = "US";
+
     ///////////////////////////////////////////////////////////////////////////////////
     //
     // STATE
@@ -127,7 +134,8 @@ public class LuceneSupportPermsTest exte
     {
         TestSuite suite = (TestSuite) TestConfiguration.embeddedSuite(LuceneSupportPermsTest.class);
 
-        Test        secureTest = new SecurityManagerSetup( suite, POLICY_FILE );
+        Test        localizedTest = new LocaleTestSetup( suite, new Locale( LANGUAGE, COUNTRY ) );
+        Test        secureTest = new SecurityManagerSetup( localizedTest, POLICY_FILE );
         Test        authenticatedTest = DatabasePropertyTestSetup.builtinAuthentication
             ( secureTest, LEGAL_USERS, "LuceneSupportPermissions" );
         Test        authorizedTest = TestConfiguration.sqlAuthorizationDecorator( authenticatedTest );
@@ -162,7 +170,8 @@ public class LuceneSupportPermsTest exte
         goodStatement( dboConnection, LOAD_TOOL );
 
         // can't update a non-existent index
-        expectExecutionError( ruthConnection, NONEXISTENT_INDEX, "call LuceneSupport.updateIndex( 'ruth', 'poems', 'poemText' )" );
+        expectExecutionError
+            ( ruthConnection, NONEXISTENT_INDEX, "call LuceneSupport.updateIndex( 'ruth', 'poems', 'poemText', null )" );
 
         // alice does not have permission to index a table owned by ruth
         expectExecutionError( aliceConnection, LACK_COLUMN_PRIV, INDEX_POEMS );
@@ -174,11 +183,12 @@ public class LuceneSupportPermsTest exte
         expectExecutionError( ruthConnection, FUNCTION_EXISTS, INDEX_POEMS );
 
         // can't update a non-existent index
-        expectExecutionError( ruthConnection, NONEXISTENT_INDEX, "call LuceneSupport.updateIndex( 'ruth', 'poems', 'foo' )" );
-        expectExecutionError( ruthConnection, NONEXISTENT_INDEX, "call LuceneSupport.updateIndex( 'ruth', 'poems', 'originalAuthor' )" );
+        expectExecutionError( ruthConnection, NONEXISTENT_INDEX, "call LuceneSupport.updateIndex( 'ruth', 'poems', 'foo', null )" );
+        expectExecutionError
+            ( ruthConnection, NONEXISTENT_INDEX, "call LuceneSupport.updateIndex( 'ruth', 'poems', 'originalAuthor', null )" );
 
         // alice can't view an index created by ruth
-        String  viewPoemsIndex = "select * from table ( ruth.poems__poemText( 'star', 0 ) ) luceneResults";
+        String  viewPoemsIndex = "select * from table ( ruth.poems__poemText( 'star', 0 ) ) luceneResults order by poemID";
         expectExecutionError( aliceConnection, LACK_EXECUTE_PRIV, viewPoemsIndex );
 
         // but ruth can
@@ -188,8 +198,9 @@ public class LuceneSupportPermsTest exte
              viewPoemsIndex,
              new String[][]
              {
-                 { "5", "5", "4", "0.3304931" },
-                 { "3", "3", "2", "0.2832798" },
+                 { "3", "3", "2", "0.22933942" },
+                 { "4", "4", "3", "0.22933942" },
+                 { "5", "5", "4", "0.26756266" },
              },
              false
              );
@@ -275,11 +286,12 @@ public class LuceneSupportPermsTest exte
         }
 
         // but alice still needs select privilege on the base table columns
-        String  viewPoemsIndex = "select * from table ( ruth.poems__poemText( 'star', 0 ) ) luceneResults";
+        String  viewPoemsIndex = "select * from table ( ruth.poems__poemText( 'star', 0 ) ) luceneResults order by poemid";
         String[][]  viewPoemsIndexResults = new String[][]
             {
-                { "5", "5", "4", "0.3304931" },
-                { "3", "3", "2", "0.2832798" },
+                { "3", "3", "2", "0.22933942" },
+                { "4", "4", "3", "0.22933942" },
+                { "5", "5", "4", "0.26756266" },
             };
 
         // now alice can view the index
@@ -353,9 +365,9 @@ public class LuceneSupportPermsTest exte
         expectExecutionError( dboConnection, DOUBLE_LOAD_ILLEGAL, LOAD_TOOL );
 
         // cannot index non-existent table or column
-        expectExecutionError( ruthConnection, NOT_INDEXABLE, "call LuceneSupport.createIndex( 'ruth', 'foo', 'poemText' )" );
-        expectExecutionError( ruthConnection, NOT_INDEXABLE, "call LuceneSupport.createIndex( 'ruth', 'poems', 'fooText' )" );
-        expectExecutionError( ruthConnection, NOT_INDEXABLE, "call LuceneSupport.createIndex( 'ruth', 'poems', 'versionStamp' )" );
+        expectExecutionError( ruthConnection, NOT_INDEXABLE, "call LuceneSupport.createIndex( 'ruth', 'foo', 'poemText', null )" );
+        expectExecutionError( ruthConnection, NOT_INDEXABLE, "call LuceneSupport.createIndex( 'ruth', 'poems', 'fooText', null )" );
+        expectExecutionError( ruthConnection, NOT_INDEXABLE, "call LuceneSupport.createIndex( 'ruth', 'poems', 'versionStamp', null )" );
 
         // cannot drop non-existent index
         expectExecutionError( ruthConnection, NONEXISTENT_OBJECT, "call LuceneSupport.dropIndex( 'ruth', 'foo', 'poemText' )" );
@@ -423,8 +435,9 @@ public class LuceneSupportPermsTest exte
              "order by i.rank desc\n",
              new String[][]
              {
-                 { "Walt Whitman", "0.3304931" },
-                 { "John Milton", "0.2832798" },
+                 { "Walt Whitman", "0.26756266" },
+                 { "Lord Byron", "0.22933942" },
+                 { "John Milton", "0.22933942" },
              },
              false
              );
@@ -469,6 +482,102 @@ public class LuceneSupportPermsTest exte
         dropSchema( ruthConnection );
     }
     
+    /**
+     * <p>
+     * Test that you can change the Analyzer.
+     * </p>
+     */
+    public  void    test_006_changeAnalyzer()
+        throws Exception
+    {
+        Connection  dboConnection = openUserConnection( TEST_DBO );
+        Connection  ruthConnection = openUserConnection( RUTH );
+
+        createSchema( ruthConnection, Types.INTEGER );
+        goodStatement( dboConnection, LOAD_TOOL );
+        goodStatement( ruthConnection, INDEX_POEMS );
+
+        // verify that we are the correct locale
+        assertResults
+            (
+             ruthConnection,
+             "values ( getDatabaseLocale() )",
+             new String[][]
+             {
+                 { LANGUAGE + "_" + COUNTRY },
+             },
+             false
+             );
+        
+
+        String  query =
+            "select p.originalAuthor, i.rank\n" +
+            "from ruth.poems p, table ( ruth.poems__poemText( 'star', 0 ) ) i\n" +
+            "where p.poemID = i.poemID and p.versionStamp = i.versionStamp\n" +
+            "order by i.rank desc\n";
+
+        assertResults
+            (
+             ruthConnection,
+             query,
+             new String[][]
+             {
+                 { "Walt Whitman", "0.26756266" },
+                 { "Lord Byron", "0.22933942" },
+                 { "John Milton", "0.22933942" },
+             },
+             false
+             );
+
+        // now switch the Analyzer and re-run the query
+        goodStatement
+            ( ruthConnection,
+              "call LuceneSupport.updateIndex( 'ruth', 'poems', 'poemText', 'org.apache.derby.optional.LuceneUtils.standardAnalyzer' )" );
+
+        assertResults
+            (
+             ruthConnection,
+             query,
+             new String[][]
+             {
+                 { "Walt Whitman", "0.3304931" },
+                 { "John Milton", "0.2832798" },
+             },
+             false
+             );
+
+        //
+        // Add another index and inspect the values of listIndexes()
+        //
+        goodStatement( ruthConnection, "call LuceneSupport.createIndex( 'ruth', 'poems', 'originalAuthor', null )" );
+        assertResults
+            (
+             ruthConnection,
+             "select schemaName, tableName, columnName, luceneVersion, analyzer, analyzerMaker\n" +
+             "from table( LuceneSupport.listIndexes() ) l\n" +
+             "order by schemaName, tableName, columnName\n",
+             new String[][]
+             {
+                 {
+                     "RUTH", "POEMS", "ORIGINALAUTHOR", LUCENE_VERSION,
+                     "org.apache.lucene.analysis.en.EnglishAnalyzer",
+                     "org.apache.derby.optional.LuceneUtils.defaultAnalyzer",
+                 },
+                 {
+                     "RUTH", "POEMS", "POEMTEXT", LUCENE_VERSION,
+                     "org.apache.lucene.analysis.standard.StandardAnalyzer",
+                     "org.apache.derby.optional.LuceneUtils.standardAnalyzer",
+                 },
+             },
+             false
+             );
+
+        goodStatement( ruthConnection, DROP_POEMS_INDEX );
+        goodStatement( ruthConnection, "call LuceneSupport.dropIndex( 'ruth', 'poems', 'originalAuthor' )" );
+        goodStatement( dboConnection, UNLOAD_TOOL );
+        dropSchema( ruthConnection );
+    }
+
     ///////////////////////////////////////////////////////////////////////////////////
     //
     // MINIONS
@@ -478,6 +587,7 @@ public class LuceneSupportPermsTest exte
     private void    createSchema( Connection ruthConnection, int jdbcType )  throws Exception
     {
         createPoemsTable( ruthConnection, jdbcType );
+        createLocaleFunction( ruthConnection );
     }
     private void    createPoemsTable( Connection conn, int jdbcType )
         throws Exception
@@ -539,6 +649,18 @@ public class LuceneSupportPermsTest exte
         ps.close();
     }
 
+    private void    createLocaleFunction( Connection conn )
+        throws Exception
+    {
+        goodStatement
+            (
+             conn,
+             "create function getDatabaseLocale() returns varchar( 20 )\n" +
+             "language java parameter style java reads sql data\n" +
+             "external name 'org.apache.derbyTesting.functionTests.tests.lang.LuceneSupportPermsTest.getDatabaseLocale()'\n"
+             );
+    }
+    
     private String  getType( int jdbcType ) throws Exception
     {
         switch( jdbcType )
@@ -636,6 +758,7 @@ public class LuceneSupportPermsTest exte
     private void    dropSchema( Connection ruthConnection )    throws Exception
     {
         goodStatement( ruthConnection, "drop table poems" );
+        goodStatement( ruthConnection, "drop function getDatabaseLocale" );
     }
     
     ///////////////////////////////////////////////////////////////////////////////////
@@ -644,6 +767,13 @@ public class LuceneSupportPermsTest exte
     //
     ///////////////////////////////////////////////////////////////////////////////////
 
+    /** Get the database locale */
+    public  static  String  getDatabaseLocale()
+        throws SQLException
+    {
+        return ConnectionUtil.getCurrentLCC().getDatabase().getLocale().toString();
+    }
+    
     public  static  String  toString( byte[] value )
     {
         if ( value == null ) { return null; }

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneSupportTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneSupportTest.java?rev=1583032&r1=1583031&r2=1583032&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneSupportTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LuceneSupportTest.java Sat Mar 29 17:32:18 2014
@@ -60,7 +60,7 @@ public class LuceneSupportTest extends B
 		Statement s = createStatement();
 	    
 		cSt = prepareCall
-            ( "call LuceneSupport.createIndex('lucenetest','titles','title')" );
+            ( "call LuceneSupport.createIndex('lucenetest','titles','title', null )" );
 	    assertUpdateCount(cSt, 0);
 	    
 	    String[][] expectedRows = new String[][]
@@ -125,7 +125,7 @@ public class LuceneSupportTest extends B
 		Statement s = createStatement();
 		
 		cSt = prepareCall
-            ( "call LuceneSupport.createIndex('lucenetest','titles','title')" );
+            ( "call LuceneSupport.createIndex('lucenetest','titles','title', null)" );
 	    assertUpdateCount(cSt, 0);
 
 	    JDBC.assertEmpty
@@ -150,7 +150,7 @@ public class LuceneSupportTest extends B
              );
 	    
 		cSt = prepareCall
-            ( "call LuceneSupport.updateIndex('lucenetest','titles','title')" );
+            ( "call LuceneSupport.updateIndex('lucenetest','titles','title', null)" );
 	    assertUpdateCount(cSt, 0);
 
 	    String[][] expectedRows = new String[][]
@@ -178,11 +178,11 @@ public class LuceneSupportTest extends B
 		Statement s = createStatement();
 
 	    cSt = prepareCall
-            ( "call LuceneSupport.createIndex('lucenetest','titles','title')" );
+            ( "call LuceneSupport.createIndex('lucenetest','titles','title', null)" );
 	    assertUpdateCount(cSt, 0);
 	    
 		cSt = prepareCall
-            ( "call LuceneSupport.createIndex('lucenetest','titles','author')" );
+            ( "call LuceneSupport.createIndex('lucenetest','titles','author', null)" );
 	    assertUpdateCount(cSt, 0);
 	    
 	    // leave out lastmodified as the date will change