diff --git a/jOOQ-test/src/org/jooq/test/jOOQOracleTest.java b/jOOQ-test/src/org/jooq/test/jOOQOracleTest.java index f7ba7d5cdc..dbe072b98f 100644 --- a/jOOQ-test/src/org/jooq/test/jOOQOracleTest.java +++ b/jOOQ-test/src/org/jooq/test/jOOQOracleTest.java @@ -76,6 +76,8 @@ import static org.jooq.test.oracle.generatedclasses.test.udt.UAuthorType.countBo import static org.jooq.test.oracle.generatedclasses.test.udt.UAuthorType.load; import static org.jooq.test.oracle2.generatedclasses.Tables.DATE_AS_TIMESTAMP_T_976; import static org.jooq.test.oracle2.generatedclasses.udt.DateAsTimestampT_976ObjectType.DATE_AS_TIMESTAMP_T_976_OBJECT_TYPE; +import static org.jooq.util.oracle.OracleFactory.contains; +import static org.jooq.util.oracle.OracleFactory.score; import static org.jooq.util.oracle.OracleFactory.sysContext; import java.math.BigDecimal; @@ -1294,4 +1296,21 @@ public class jOOQOracleTest extends jOOQAbstractTest< assertEquals(result1, result2); } + + @Test + public void testOracleText() throws Exception { + + // [#816] CONTAINS() tests + Result result1 = + create().select(TBook_TITLE(), score(2)) + .from(TBook()) + .where(contains(TBook_TITLE(), "Alq%").greaterThan(BigDecimal.ZERO)) + .or(contains(TBook_TITLE(), "O%", 2).greaterThan(BigDecimal.ZERO)) + .orderBy(TBook_ID()) + .fetch(); + + assertEquals(1, result1.size()); + assertEquals("O Alquimista", result1.getValue(0, TBook_TITLE())); + assertEquals(1, result1.getValue(0, score(2)).compareTo(BigDecimal.ZERO)); + } } diff --git a/jOOQ-test/src/org/jooq/test/oracle/create.sql b/jOOQ-test/src/org/jooq/test/oracle/create.sql index 09f0ec2a6a..c14a69692e 100644 --- a/jOOQ-test/src/org/jooq/test/oracle/create.sql +++ b/jOOQ-test/src/org/jooq/test/oracle/create.sql @@ -1751,4 +1751,6 @@ create or replace synonym v_author_synonym for v_author/ create or replace synonym p_unused_synonym for p_unused/ create or replace synonym t_author_synonym_synonym for t_author_synonym/ create or replace public synonym t_author_public_synonym for t_author/ -create or replace public synonym t_author for t_author/ \ No newline at end of file +create or replace public synonym t_author for t_author/ + +CREATE INDEX i_book_title_context ON t_book(title) INDEXTYPE IS CTXSYS.CONTEXT/ \ No newline at end of file diff --git a/jOOQ-test/src/org/jooq/test/oracle/reset.sql b/jOOQ-test/src/org/jooq/test/oracle/reset.sql index 94649ab152..6f227e7ee5 100644 --- a/jOOQ-test/src/org/jooq/test/oracle/reset.sql +++ b/jOOQ-test/src/org/jooq/test/oracle/reset.sql @@ -97,3 +97,5 @@ INSERT INTO t_directory VALUES ( 1, null, 1, 'C:')/ INSERT INTO t_directory VALUES (24, 19, 1, 'lib')/ INSERT INTO t_directory VALUES (25, 24, 0, 'javaws.jar')/ INSERT INTO t_directory VALUES (26, 24, 0, 'rt.jar')/ + +ALTER INDEX i_book_title_context REBUILD/ \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/Field.java b/jOOQ/src/main/java/org/jooq/Field.java index 088e3726c3..6e7e06d32e 100644 --- a/jOOQ/src/main/java/org/jooq/Field.java +++ b/jOOQ/src/main/java/org/jooq/Field.java @@ -56,6 +56,7 @@ import java.util.Map; import org.jooq.impl.Factory; import org.jooq.types.Interval; +import org.jooq.util.oracle.OracleFactory; /** * A field used in tables and conditions @@ -814,14 +815,17 @@ public interface Field extends NamedTypeProviderQueryPart, AliasProviderval(1133).contains(13) *

- * If you're using {@link SQLDialect#POSTGRES}, then you can use this method also to express the "ARRAY contains" operator. For example: - *

+     * If you're using {@link SQLDialect#POSTGRES}, then you can use this method
+     * also to express the "ARRAY contains" operator. For example: 
      * // Use this expression
      * val(new Integer[] { 1, 2, 3 }).contains(new Integer[] { 1, 2 })
      *
      * // ... to render this SQL
      * ARRAY[1, 2, 3] @> ARRAY[1, 2]
      * 
+ *

+ * Note, this does not correspond to the Oracle Text CONTAINS() + * function. Refer to {@link OracleFactory#contains(Field, String)} instead. * * @see Factory#escape(String, char) * @see #like(String, char) @@ -838,14 +842,17 @@ public interface Field extends NamedTypeProviderQueryPart, AliasProviderval(1133).contains(13) *

- * If you're using {@link SQLDialect#POSTGRES}, then you can use this method also to express the "ARRAY contains" operator. For example: - *

+     * If you're using {@link SQLDialect#POSTGRES}, then you can use this method
+     * also to express the "ARRAY contains" operator. For example: 
      * // Use this expression
      * val(new Integer[] { 1, 2, 3 }).contains(new Integer[] { 1, 2 })
      *
      * // ... to render this SQL
      * ARRAY[1, 2, 3] @> ARRAY[1, 2]
      * 
+ *

+ * Note, this does not correspond to the Oracle Text CONTAINS() + * function. Refer to {@link OracleFactory#contains(Field, String)} instead. * * @see Factory#escape(Field, char) * @see #like(Field, char) diff --git a/jOOQ/src/main/java/org/jooq/impl/Factory.java b/jOOQ/src/main/java/org/jooq/impl/Factory.java index dcb0954f43..de6d92ca87 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Factory.java +++ b/jOOQ/src/main/java/org/jooq/impl/Factory.java @@ -1943,7 +1943,7 @@ public class Factory implements FactoryOperations { * {@inheritDoc} */ @Override - public MergeKeyStep mergeInto(Table table, Field... fields) { + public final MergeKeyStep mergeInto(Table table, Field... fields) { return mergeInto(table, Arrays.asList(fields)); } @@ -1951,7 +1951,7 @@ public class Factory implements FactoryOperations { * {@inheritDoc} */ @Override - public MergeKeyStep mergeInto(Table table, Collection> fields) { + public final MergeKeyStep mergeInto(Table table, Collection> fields) { return new MergeImpl(this, table, fields); } @@ -5896,14 +5896,14 @@ public class Factory implements FactoryOperations { /** * Null-safety of a field */ - static Field nullSafe(Field field) { + protected static Field nullSafe(Field field) { return field == null ? val((T) null) : field; } /** * Null-safety of a field */ - static Field[] nullSafe(Field... fields) { + protected static Field[] nullSafe(Field... fields) { Field[] result = new Field[fields.length]; for (int i = 0; i < fields.length; i++) { @@ -5917,7 +5917,7 @@ public class Factory implements FactoryOperations { * Get a default data type if a field is null */ @SuppressWarnings("unchecked") - static DataType nullSafeDataType(Field field) { + protected static DataType nullSafeDataType(Field field) { return (DataType) (field == null ? SQLDataType.OTHER : field.getDataType()); } diff --git a/jOOQ/src/main/java/org/jooq/util/oracle/OracleFactory.java b/jOOQ/src/main/java/org/jooq/util/oracle/OracleFactory.java index 5cc936a0dc..4c02b014bf 100644 --- a/jOOQ/src/main/java/org/jooq/util/oracle/OracleFactory.java +++ b/jOOQ/src/main/java/org/jooq/util/oracle/OracleFactory.java @@ -35,6 +35,9 @@ */ package org.jooq.util.oracle; +import static org.jooq.SQLDialect.ORACLE; + +import java.math.BigDecimal; import java.sql.Connection; import javax.sql.DataSource; @@ -42,6 +45,7 @@ import javax.sql.DataSource; import org.jooq.Field; import org.jooq.SQLDialect; import org.jooq.SchemaMapping; +import org.jooq.Support; import org.jooq.conf.Settings; import org.jooq.impl.Factory; import org.jooq.impl.SQLDataType; @@ -148,6 +152,7 @@ public class OracleFactory extends Factory { /** * Retrieve the Oracle-specific ROWNUM pseudo-field */ + @Support(ORACLE) public static Field rownum() { return field("rownum", Integer.class); } @@ -155,6 +160,7 @@ public class OracleFactory extends Factory { /** * Retrieve the Oracle-specific ROWID pseudo-field */ + @Support(ORACLE) public static Field rowid() { return field("rowid", String.class); } @@ -166,6 +172,7 @@ public class OracleFactory extends Factory { /** * The Oracle-specific SYS_CONTEXT function */ + @Support(ORACLE) public static Field sysContext(String namespace, String parameter) { return function("sys_context", SQLDataType.VARCHAR, val(namespace), val(parameter)); } @@ -173,7 +180,69 @@ public class OracleFactory extends Factory { /** * The Oracle-specific SYS_CONTEXT function */ + @Support(ORACLE) public static Field sysContext(String namespace, String parameter, int length) { return function("sys_context", SQLDataType.VARCHAR, val(namespace), val(parameter), val(length)); } + + // ------------------------------------------------------------------------- + // Oracle Text functions + // ------------------------------------------------------------------------- + + /** + * The Oracle-Text specific CONTAINS function + */ + @Support(ORACLE) + public static Field contains(Field field, String query) { + return field("{contains}({0}, {1})", SQLDataType.NUMERIC, nullSafe(field), val(query)); + } + + /** + * The Oracle-Text specific CONTAINS function + */ + @Support(ORACLE) + public static Field contains(Field field, String query, int label) { + return field("{contains}({0}, {1}, {2})", SQLDataType.NUMERIC, nullSafe(field), val(query), inline(label)); + } + + /** + * The Oracle-Text specific MATCHES function + */ + @Support(ORACLE) + public static Field matches(Field field, String query) { + return field("{matches}({0}, {1})", SQLDataType.NUMERIC, nullSafe(field), val(query)); + } + + /** + * The Oracle-Text specific CONTAINS function + */ + @Support(ORACLE) + public static Field matches(Field field, String query, int label) { + return field("{matches}({0}, {1}, {2})", SQLDataType.NUMERIC, nullSafe(field), val(query), inline(label)); + } + + /** + * The Oracle-Text specific CATSEARCH function + */ + @Support(ORACLE) + public static Field catsearch(Field field, String textQuery, String structuredQuery) { + return field("{catsearch}({0}, {1}, {2})", SQLDataType.NUMERIC, nullSafe(field), val(textQuery), val(structuredQuery)); + } + + /** + * The Oracle-Text specific SCORE function + */ + @Support(ORACLE) + public static Field score(int label) { + return field("{score}({0})", SQLDataType.NUMERIC, inline(label)); + } + + /** + * The Oracle-Text specific MATCH_SCORE function + */ + @Support(ORACLE) + public static Field matchScore(int label) { + return field("{match_score}({0})", SQLDataType.NUMERIC, inline(label)); + } + }