Repository: crate/crate
Issue: Filtering on a column with `INDEX OFF` doesn't behave correctly

### CrateDB version

5.4.0

### Problem description

Filtering on a column with `INDEX OFF` doesn't behave consistently.

### Steps to Reproduce

```
cr> create table t(a int INDEX OFF);
CREATE OK, 1 row affected  (0.327 sec)
```

```
cr> select * from t where a = 1;
SQLParseException[Cannot search on field [a] since it is not indexed.]
```
this seems fine, but:

```
cr> select * from t where a > 1;
+---+
| a |
+---+
+---+
SELECT 0 rows in set (0.008 sec)
```
and:
```
cr> insert into t(a) values(2), (3);
INSERT OK, 2 rows affected  (0.043 sec)
cr> refresh table t;
REFRESH OK, 1 row affected  (0.003 sec)
cr> select * from t where a > 1;
+---+
| a |
+---+
+---+
SELECT 0 rows in set (0.003 sec)
cr> select * from t where a + 1 > 1;
+---+
| a |
+---+
| 3 |
| 2 |
+---+
SELECT 2 rows in set (0.008 sec)
```


Changed files:
server/src/main/java/io/crate/types/FloatVectorType.java
server/src/main/java/io/crate/expression/scalar/SubscriptFunction.java
server/src/main/java/io/crate/types/BooleanType.java
server/src/main/java/io/crate/expression/operator/any/AnyEqOperator.java
server/src/main/java/io/crate/types/LongEqQuery.java
server/src/main/java/io/crate/types/StringType.java
server/src/main/java/io/crate/types/IpType.java
server/src/main/java/io/crate/expression/operator/any/AnyNeqOperator.java
server/src/test/java/io/crate/integrationtests/DDLIntegrationTest.java
server/src/main/java/io/crate/types/EqQuery.java
server/src/main/java/io/crate/execution/engine/collect/collectors/OptimizeQueryForSearchAfter.java
server/src/main/java/io/crate/expression/operator/EqOperator.java
server/src/main/java/io/crate/types/BitStringType.java
server/src/main/java/io/crate/types/FloatType.java
server/src/test/java/io/crate/expression/operator/EqOperatorTest.java
server/src/test/java/io/crate/integrationtests/LuceneQueryBuilderIntegrationTest.java
server/src/main/java/io/crate/expression/operator/CmpOperator.java
server/src/main/java/io/crate/types/IntEqQuery.java
server/src/main/java/io/crate/types/DoubleType.java

diff --git a/server/src/main/java/io/crate/execution/engine/collect/collectors/OptimizeQueryForSearchAfter.java b/server/src/main/java/io/crate/execution/engine/collect/collectors/OptimizeQueryForSearchAfter.java
index c5016973f7..29e5959a94 100644
--- a/server/src/main/java/io/crate/execution/engine/collect/collectors/OptimizeQueryForSearchAfter.java
+++ b/server/src/main/java/io/crate/execution/engine/collect/collectors/OptimizeQueryForSearchAfter.java
@@ -82,20 +82,20 @@ public class OptimizeQueryForSearchAfter implements Function<FieldDoc, Query> {
                     BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
                     booleanQuery.add(new MatchAllDocsQuery(), BooleanClause.Occur.MUST);
                     if (orderBy.reverseFlags()[i]) {
-                        booleanQuery.add(eqQuery.rangeQuery(columnName, null, value, false, true, ref.hasDocValues()),
+                        booleanQuery.add(eqQuery.rangeQuery(columnName, null, value, false, true, ref.hasDocValues(), ref.indexType()),
                                          BooleanClause.Occur.MUST_NOT);
                     } else {
-                        booleanQuery.add(eqQuery.rangeQuery(columnName, value, null, true, false, ref.hasDocValues()),
+                        booleanQuery.add(eqQuery.rangeQuery(columnName, value, null, true, false, ref.hasDocValues(), ref.indexType()),
                                          BooleanClause.Occur.MUST_NOT);
                     }
                     orderQuery = booleanQuery.build();
                 } else {
                     if (orderBy.reverseFlags()[i]) {
                         orderQuery = eqQuery.rangeQuery(
-                                columnName, value, null, false, false, ref.hasDocValues());
+                                columnName, value, null, false, false, ref.hasDocValues(), ref.indexType());
                     } else {
                         orderQuery = eqQuery.rangeQuery(
-                                columnName, null, value, false, false, ref.hasDocValues());
+                                columnName, null, value, false, false, ref.hasDocValues(), ref.indexType());
                     }
                 }
                 queryBuilder.add(orderQuery, BooleanClause.Occur.MUST);
diff --git a/server/src/main/java/io/crate/expression/operator/CmpOperator.java b/server/src/main/java/io/crate/expression/operator/CmpOperator.java
index 3882583e5b..172ee7b94d 100644
--- a/server/src/main/java/io/crate/expression/operator/CmpOperator.java
+++ b/server/src/main/java/io/crate/expression/operator/CmpOperator.java
@@ -94,13 +94,13 @@ public final class CmpOperator extends Operator<Object> {
         String field = ref.column().fqn();
         return switch (functionName) {
             case GtOperator.NAME -> eqQuery.rangeQuery(
-                    field, value, null, false, false, ref.hasDocValues());
+                    field, value, null, false, false, ref.hasDocValues(), ref.indexType());
             case GteOperator.NAME -> eqQuery.rangeQuery(
-                    field, value, null, true, false, ref.hasDocValues());
+                    field, value, null, true, false, ref.hasDocValues(), ref.indexType());
             case LtOperator.NAME ->
-                    eqQuery.rangeQuery(field, null, value, false, false, ref.hasDocValues());
+                    eqQuery.rangeQuery(field, null, value, false, false, ref.hasDocValues(), ref.indexType());
             case LteOperator.NAME ->
-                    eqQuery.rangeQuery(field, null, value, false, true, ref.hasDocValues());
+                    eqQuery.rangeQuery(field, null, value, false, true, ref.hasDocValues(), ref.indexType());
             default -> throw new IllegalArgumentException(functionName + " is not a supported comparison operator");
         };
     }
diff --git a/server/src/main/java/io/crate/expression/operator/EqOperator.java b/server/src/main/java/io/crate/expression/operator/EqOperator.java
index 66b04f1f7b..7b12193ccf 100644
--- a/server/src/main/java/io/crate/expression/operator/EqOperator.java
+++ b/server/src/main/java/io/crate/expression/operator/EqOperator.java
@@ -56,7 +56,6 @@ import io.crate.expression.scalar.NumTermsPerDocQuery;
 import io.crate.expression.symbol.Function;
 import io.crate.expression.symbol.Literal;
 import io.crate.expression.symbol.Symbol;
-import io.crate.lucene.LuceneQueryBuilder;
 import io.crate.lucene.LuceneQueryBuilder.Context;
 import io.crate.metadata.IndexType;
 import io.crate.metadata.NodeContext;
@@ -147,26 +146,30 @@ public final class EqOperator extends Operator<Object> {
             return new MatchNoDocsQuery("`" + fqn + "` = null is always null");
         }
         DataType<?> dataType = ref.valueType();
-        if (dataType.id() != ObjectType.ID && dataType.id() != ArrayType.ID && ref.indexType() == IndexType.NONE) {
-            throw new IllegalArgumentException(
-                "Cannot search on field [" + fqn + "] since it is not indexed.");
-        }
         return switch (dataType.id()) {
-            case ObjectType.ID -> refEqObject(function, fqn, (ObjectType) dataType, (Map<String, Object>) value, context);
-            case ArrayType.ID -> termsAndGenericFilter(
+            case ObjectType.ID -> refEqObject(
+                function,
+                fqn,
+                (ObjectType) dataType,
+                (Map<String, Object>) value,
+                context,
+                ref.hasDocValues(),
+                ref.indexType());
+            case ArrayType.ID -> refEqArray(
                 function,
                 ref.column().fqn(),
                 ArrayType.unnest(dataType),
                 (Collection<?>) value,
-                context
-            );
-            default -> fromPrimitive(dataType, fqn, value);
+                context,
+                ref.hasDocValues(),
+                ref.indexType());
+            default -> fromPrimitive(dataType, fqn, value, ref.hasDocValues(), ref.indexType());
         };
     }
 
     @Nullable
     @SuppressWarnings("unchecked")
-    public static Query termsQuery(String column, DataType<?> type, Collection<?> values) {
+    public static Query termsQuery(String column, DataType<?> type, Collection<?> values, boolean hasDocValues, IndexType indexType) {
         List<?> nonNullValues = values.stream().filter(Objects::nonNull).toList();
         if (nonNullValues.isEmpty()) {
             return null;
@@ -193,20 +196,29 @@ public final class EqOperator extends Operator<Object> {
                 column,
                 nonNullValues.stream().map(x -> new BytesRef(((BitString) x).bitSet().toByteArray())).toList()
             );
-            default -> booleanShould(column, type, nonNullValues);
+            default -> booleanShould(column, type, nonNullValues, hasDocValues, indexType);
         };
     }
 
     @Nullable
-    private static Query booleanShould(String column, DataType<?> type, Collection<?> values) {
+    private static Query booleanShould(String column,
+                                       DataType<?> type,
+                                       Collection<?> values,
+                                       boolean hasDocValues,
+                                       IndexType indexType) {
         BooleanQuery.Builder builder = new BooleanQuery.Builder();
         for (var term : values) {
-            builder.add(EqOperator.fromPrimitive(type, column, term), Occur.SHOULD);
+            builder.add(EqOperator.fromPrimitive(type, column, term, hasDocValues, indexType), Occur.SHOULD);
         }
         return new ConstantScoreQuery(builder.build());
     }
 
-    private static Query termsAndGenericFilter(Function function, String column, DataType<?> elementType, Collection<?> values, LuceneQueryBuilder.Context context) {
+    private static Query refEqArray(Function function,
+                                    String column,
+                                    DataType<?> elementType, Collection<?> values,
+                                    Context context,
+                                    boolean hasDocValues,
+                                    IndexType indexType) {
         MappedFieldType fieldType = context.getFieldTypeOrNull(column);
         if (fieldType == null) {
             if (elementType.id() == ObjectType.ID) {
@@ -237,7 +249,7 @@ public final class EqOperator extends Operator<Object> {
             // wrap boolTermsFilter and genericFunction filter in an additional BooleanFilter to control the ordering of the filters
             // termsFilter is applied first
             // afterwards the more expensive genericFunctionFilter
-            Query termsQuery = termsQuery(column, elementType, values);
+            Query termsQuery = termsQuery(column, elementType, values, hasDocValues, indexType);
             if (termsQuery == null) {
                 return genericFunctionFilter;
             }
@@ -248,7 +260,7 @@ public final class EqOperator extends Operator<Object> {
     }
 
     @SuppressWarnings("unchecked")
-    public static Query fromPrimitive(DataType<?> type, String column, Object value) {
+    public static Query fromPrimitive(DataType<?> type, String column, Object value, boolean hasDocValues, IndexType indexType) {
         if (column.equals(DocSysColumns.ID.name())) {
             return new TermQuery(new Term(column, Uid.encodeId((String) value)));
         }
@@ -257,7 +269,7 @@ public final class EqOperator extends Operator<Object> {
         if (eqQuery == null) {
             return null;
         }
-        return ((EqQuery<Object>) eqQuery).termQuery(column, value);
+        return ((EqQuery<Object>) eqQuery).termQuery(column, value, hasDocValues, indexType);
     }
 
     /**
@@ -279,7 +291,9 @@ public final class EqOperator extends Operator<Object> {
                                      String fqn,
                                      ObjectType type,
                                      Map<String, Object> value,
-                                     LuceneQueryBuilder.Context context) {
+                                     Context context,
+                                     boolean hasDocValues,
+                                     IndexType indexType) {
         BooleanQuery.Builder boolBuilder = new BooleanQuery.Builder();
         int preFilters = 0;
         for (Map.Entry<String, Object> entry : value.entrySet()) {
@@ -292,9 +306,10 @@ public final class EqOperator extends Operator<Object> {
             String fqNestedColumn = fqn + '.' + key;
             Query innerQuery;
             if (DataTypes.isArray(innerType)) {
-                innerQuery = termsAndGenericFilter(eq, fqNestedColumn, innerType, (Collection<?>) entry.getValue(), context);
+                innerQuery = refEqArray(
+                    eq, fqNestedColumn, innerType, (Collection<?>) entry.getValue(), context, hasDocValues, indexType);
             } else {
-                innerQuery = fromPrimitive(innerType, fqNestedColumn, entry.getValue());
+                innerQuery = fromPrimitive(innerType, fqNestedColumn, entry.getValue(), hasDocValues, indexType);
             }
             if (innerQuery == null) {
                 continue;
diff --git a/server/src/main/java/io/crate/expression/operator/any/AnyEqOperator.java b/server/src/main/java/io/crate/expression/operator/any/AnyEqOperator.java
index 215f6a8da8..5103fdcdfe 100644
--- a/server/src/main/java/io/crate/expression/operator/any/AnyEqOperator.java
+++ b/server/src/main/java/io/crate/expression/operator/any/AnyEqOperator.java
@@ -68,7 +68,7 @@ public final class AnyEqOperator extends AnyOperator {
             return new MatchNoDocsQuery("column does not exist in this index");
         }
         DataType<?> innerType = ArrayType.unnest(probe.valueType());
-        return EqOperator.termsQuery(columnName, innerType, values);
+        return EqOperator.termsQuery(columnName, innerType, values, probe.hasDocValues(), probe.indexType());
     }
 
     @Override
@@ -85,7 +85,12 @@ public final class AnyEqOperator extends AnyOperator {
             // [1, 2] = any(nested_array_ref)
             return arrayLiteralEqAnyArray(any, candidates, probe.value(), context);
         }
-        return EqOperator.fromPrimitive(ArrayType.unnest(candidates.valueType()), candidates.column().fqn(), probe.value());
+        return EqOperator.fromPrimitive(
+            ArrayType.unnest(candidates.valueType()),
+            candidates.column().fqn(),
+            probe.value(),
+            candidates.hasDocValues(),
+            candidates.indexType());
     }
 
     private static Query arrayLiteralEqAnyArray(Function function,
@@ -97,8 +102,9 @@ public final class AnyEqOperator extends AnyOperator {
         Query termsQuery = EqOperator.termsQuery(
             candidates.column().fqn(),
             ArrayType.unnest(candidates.valueType()),
-            terms
-        );
+            terms,
+            candidates.hasDocValues(),
+            candidates.indexType());
         Query genericFunctionFilter = LuceneQueryBuilder.genericFunctionFilter(function, context);
         if (termsQuery == null) {
             return genericFunctionFilter;
diff --git a/server/src/main/java/io/crate/expression/operator/any/AnyNeqOperator.java b/server/src/main/java/io/crate/expression/operator/any/AnyNeqOperator.java
index 94bc967a96..e3fba3f4e4 100644
--- a/server/src/main/java/io/crate/expression/operator/any/AnyNeqOperator.java
+++ b/server/src/main/java/io/crate/expression/operator/any/AnyNeqOperator.java
@@ -65,7 +65,14 @@ public final class AnyNeqOperator extends AnyOperator {
 
         BooleanQuery.Builder andBuilder = new BooleanQuery.Builder();
         for (Object value : (Iterable<?>) candidates.value()) {
-            andBuilder.add(EqOperator.fromPrimitive(probe.valueType(), probe.column().fqn(), value), BooleanClause.Occur.MUST);
+            andBuilder.add(
+                EqOperator.fromPrimitive(
+                    probe.valueType(),
+                    probe.column().fqn(),
+                    value,
+                    probe.hasDocValues(),
+                    probe.indexType()),
+                BooleanClause.Occur.MUST);
         }
         Query exists = IsNullPredicate.refExistsQuery(probe, context, false);
         return new BooleanQuery.Builder()
@@ -96,11 +103,11 @@ public final class AnyNeqOperator extends AnyOperator {
         BooleanQuery.Builder query = new BooleanQuery.Builder();
         query.setMinimumNumberShouldMatch(1);
         query.add(
-            eqQuery.rangeQuery(columnName, value, null, false, false, candidates.hasDocValues()),
+            eqQuery.rangeQuery(columnName, value, null, false, false, candidates.hasDocValues(), candidates.indexType()),
             BooleanClause.Occur.SHOULD
         );
         query.add(
-            eqQuery.rangeQuery(columnName, null, value, false, false, candidates.hasDocValues()),
+            eqQuery.rangeQuery(columnName, null, value, false, false, candidates.hasDocValues(), candidates.indexType()),
             BooleanClause.Occur.SHOULD
         );
         return query.build();
diff --git a/server/src/main/java/io/crate/expression/scalar/SubscriptFunction.java b/server/src/main/java/io/crate/expression/scalar/SubscriptFunction.java
index ef31afd33e..d1da2a14f1 100644
--- a/server/src/main/java/io/crate/expression/scalar/SubscriptFunction.java
+++ b/server/src/main/java/io/crate/expression/scalar/SubscriptFunction.java
@@ -47,6 +47,7 @@ import io.crate.expression.symbol.Literal;
 import io.crate.expression.symbol.Symbol;
 import io.crate.lucene.LuceneQueryBuilder;
 import io.crate.lucene.LuceneQueryBuilder.Context;
+import io.crate.metadata.IndexType;
 import io.crate.metadata.NodeContext;
 import io.crate.metadata.Reference;
 import io.crate.metadata.Scalar;
@@ -224,19 +225,19 @@ public class SubscriptFunction extends Scalar<Object, Object[]> {
     }
 
     private interface PreFilterQueryBuilder {
-        Query buildQuery(String field, EqQuery<Object> eqQuery, Object value, boolean hasDocValues);
+        Query buildQuery(String field, EqQuery<Object> eqQuery, Object value, boolean hasDocValues, IndexType indexType);
     }
 
     private static final Map<String, PreFilterQueryBuilder> PRE_FILTER_QUERY_BUILDER_BY_OP = Map.of(
-        EqOperator.NAME, (field, eqQuery, value, haDocValues) -> eqQuery.termQuery(field, value),
-        GteOperator.NAME, (field, eqQuery, value, hasDocValues) ->
-                eqQuery.rangeQuery(field, value, null, true, false, hasDocValues),
-        GtOperator.NAME, (field, eqQuery, value, hasDocValues) ->
-                eqQuery.rangeQuery(field, value, null, false, false, hasDocValues),
-        LteOperator.NAME, (field, eqQuery, value, hasDocValues) ->
-                eqQuery.rangeQuery(field, null, value, false, true, hasDocValues),
-        LtOperator.NAME, (field, eqQuery, value, hasDocValues) ->
-                eqQuery.rangeQuery(field, null, value, false, false, hasDocValues)
+        EqOperator.NAME, (field, eqQuery, value, haDocValues, indexType) -> eqQuery.termQuery(field, value, haDocValues, indexType),
+        GteOperator.NAME, (field, eqQuery, value, hasDocValues, indexType) ->
+                eqQuery.rangeQuery(field, value, null, true, false, hasDocValues, indexType),
+        GtOperator.NAME, (field, eqQuery, value, hasDocValues, indexType) ->
+                eqQuery.rangeQuery(field, value, null, false, false, hasDocValues, indexType),
+        LteOperator.NAME, (field, eqQuery, value, hasDocValues, indexType) ->
+                eqQuery.rangeQuery(field, null, value, false, true, hasDocValues, indexType),
+        LtOperator.NAME, (field, eqQuery, value, hasDocValues, indexType) ->
+                eqQuery.rangeQuery(field, null, value, false, false, hasDocValues, indexType)
     );
 
     @Override
@@ -271,7 +272,7 @@ public class SubscriptFunction extends Scalar<Object, Object[]> {
             }
             BooleanQuery.Builder builder = new BooleanQuery.Builder();
             builder.add(
-                preFilterQueryBuilder.buildQuery(ref.column().fqn(), eqQuery, cmpLiteral.value(), ref.hasDocValues()),
+                preFilterQueryBuilder.buildQuery(ref.column().fqn(), eqQuery, cmpLiteral.value(), ref.hasDocValues(), ref.indexType()),
                 BooleanClause.Occur.MUST);
             builder.add(LuceneQueryBuilder.genericFunctionFilter(parent, context), BooleanClause.Occur.FILTER);
             return builder.build();
diff --git a/server/src/main/java/io/crate/types/BitStringType.java b/server/src/main/java/io/crate/types/BitStringType.java
index f6e5d69d60..8c3c2e9636 100644
--- a/server/src/main/java/io/crate/types/BitStringType.java
+++ b/server/src/main/java/io/crate/types/BitStringType.java
@@ -29,6 +29,7 @@ import java.util.Map;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
+import org.apache.lucene.document.SortedSetDocValuesField;
 import org.jetbrains.annotations.Nullable;
 
 import org.apache.lucene.document.FieldType;
@@ -45,6 +46,7 @@ import io.crate.Streamer;
 import io.crate.execution.dml.BitStringIndexer;
 import io.crate.execution.dml.ValueIndexer;
 import io.crate.metadata.ColumnIdent;
+import io.crate.metadata.IndexType;
 import io.crate.metadata.Reference;
 import io.crate.metadata.RelationName;
 import io.crate.metadata.settings.SessionSettings;
@@ -69,7 +71,10 @@ public final class BitStringType extends DataType<BitString> implements Streamer
         new EqQuery<BitString>() {
 
             @Override
-            public Query termQuery(String field, BitString value) {
+            public Query termQuery(String field, BitString value, boolean hasDocValues, IndexType indexType) {
+                if (hasDocValues) {
+                    return SortedSetDocValuesField.newSlowExactQuery(field, new BytesRef(value.bitSet().toByteArray()));
+                }
                 return new TermQuery(new Term(field, new BytesRef(value.bitSet().toByteArray())));
             }
 
@@ -79,7 +84,11 @@ public final class BitStringType extends DataType<BitString> implements Streamer
                                     BitString upperTerm,
                                     boolean includeLower,
                                     boolean includeUpper,
-                                    boolean hasDocValues) {
+                                    boolean hasDocValues,
+                                    IndexType indexType) {
+                // TODO: this should be a bug:
+                //  select * from t where a > b'001';
+                //  => UnsupportedFunctionException[Unknown function: (doc.t.a > B'001')
                 return null;
             }
         }
diff --git a/server/src/main/java/io/crate/types/BooleanType.java b/server/src/main/java/io/crate/types/BooleanType.java
index 2c2d0095ee..7618ab5ad4 100644
--- a/server/src/main/java/io/crate/types/BooleanType.java
+++ b/server/src/main/java/io/crate/types/BooleanType.java
@@ -27,6 +27,7 @@ import java.util.Map;
 import java.util.function.Function;
 
 import org.apache.lucene.document.FieldType;
+import org.apache.lucene.document.SortedNumericDocValuesField;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.TermQuery;
@@ -39,6 +40,7 @@ import io.crate.Streamer;
 import io.crate.execution.dml.BooleanIndexer;
 import io.crate.execution.dml.ValueIndexer;
 import io.crate.metadata.ColumnIdent;
+import io.crate.metadata.IndexType;
 import io.crate.metadata.Reference;
 import io.crate.metadata.RelationName;
 
@@ -57,7 +59,13 @@ public class BooleanType extends DataType<Boolean> implements Streamer<Boolean>,
         }
 
         @Override
-        public Query termQuery(String field, Boolean value) {
+        public Query termQuery(String field, Boolean value, boolean hasDocValues, IndexType indexType) {
+            assert value != null: "Cannot perform = NULL, IS NULL should be used";
+            if (hasDocValues) {
+                return SortedNumericDocValuesField.newSlowExactQuery(
+                    field,
+                    value ? 1 : 0);
+            }
             return new TermQuery(new Term(field, indexedValue(value)));
         }
 
@@ -67,7 +75,17 @@ public class BooleanType extends DataType<Boolean> implements Streamer<Boolean>,
                                 Boolean upperTerm,
                                 boolean includeLower,
                                 boolean includeUpper,
-                                boolean hasDocValues) {
+                                boolean hasDocValues,
+                                IndexType indexType) {
+            if (hasDocValues) {
+                if (lowerTerm == null || upperTerm == null) {
+                    return null;
+                }
+                return SortedNumericDocValuesField.newSlowRangeQuery(
+                    field,
+                    lowerTerm ? 1 : 0,
+                    upperTerm ? 1 : 0);
+            }
             return new TermRangeQuery(
                 field, indexedValue(lowerTerm), indexedValue(upperTerm), includeLower, includeUpper);
         }
diff --git a/server/src/main/java/io/crate/types/DoubleType.java b/server/src/main/java/io/crate/types/DoubleType.java
index dc6f32d4da..e3b652889d 100644
--- a/server/src/main/java/io/crate/types/DoubleType.java
+++ b/server/src/main/java/io/crate/types/DoubleType.java
@@ -26,10 +26,10 @@ import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.function.Function;
 
+import org.apache.lucene.document.DoubleField;
 import org.apache.lucene.document.DoublePoint;
 import org.apache.lucene.document.FieldType;
 import org.apache.lucene.document.SortedNumericDocValuesField;
-import org.apache.lucene.search.IndexOrDocValuesQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.util.NumericUtils;
 import org.apache.lucene.util.RamUsageEstimator;
@@ -40,6 +40,7 @@ import io.crate.Streamer;
 import io.crate.execution.dml.DoubleIndexer;
 import io.crate.execution.dml.ValueIndexer;
 import io.crate.metadata.ColumnIdent;
+import io.crate.metadata.IndexType;
 import io.crate.metadata.Reference;
 import io.crate.metadata.RelationName;
 
@@ -55,8 +56,16 @@ public class DoubleType extends DataType<Double> implements FixedWidthType, Stre
         new EqQuery<Double>() {
 
             @Override
-            public Query termQuery(String field, Double value) {
-                return DoublePoint.newExactQuery(field, value);
+            public Query termQuery(String field, Double value, boolean hasDocValues, IndexType indexType) {
+                boolean isIndexed = indexType != IndexType.NONE;
+                if (hasDocValues && isIndexed) {
+                    return DoubleField.newExactQuery(field, value);
+                } else if (hasDocValues) {
+                    return SortedNumericDocValuesField.newSlowExactQuery(field, NumericUtils.doubleToSortableLong(value));
+                } else if (isIndexed) {
+                    return DoublePoint.newExactQuery(field, value);
+                }
+                return null;
             }
 
             @Override
@@ -65,7 +74,8 @@ public class DoubleType extends DataType<Double> implements FixedWidthType, Stre
                                     Double upperTerm,
                                     boolean includeLower,
                                     boolean includeUpper,
-                                    boolean hasDocValues) {
+                                    boolean hasDocValues,
+                                    IndexType indexType) {
                 double lower;
                 if (lowerTerm == null) {
                     lower = Double.NEGATIVE_INFINITY;
@@ -79,16 +89,18 @@ public class DoubleType extends DataType<Double> implements FixedWidthType, Stre
                 } else {
                     upper = includeUpper ? upperTerm : DoublePoint.nextDown(upperTerm);
                 }
-                Query indexQuery = DoublePoint.newRangeQuery(field, lower, upper);
-                if (hasDocValues) {
-                    Query dvQuery = SortedNumericDocValuesField.newSlowRangeQuery(
-                            field,
-                            NumericUtils.doubleToSortableLong(lower),
-                            NumericUtils.doubleToSortableLong(upper)
-                    );
-                    return new IndexOrDocValuesQuery(indexQuery, dvQuery);
+                boolean isIndexed = indexType != IndexType.NONE;
+                if (hasDocValues && isIndexed) {
+                    return DoubleField.newRangeQuery(field, lower, upper);
+                } else if (hasDocValues) {
+                    return SortedNumericDocValuesField.newSlowRangeQuery(
+                        field,
+                        NumericUtils.doubleToSortableLong(lower),
+                        NumericUtils.doubleToSortableLong(upper));
+                } else if (isIndexed) {
+                    return DoublePoint.newRangeQuery(field, lower, upper);
                 }
-                return indexQuery;
+                return null;
             }
         }
     ) {
diff --git a/server/src/main/java/io/crate/types/EqQuery.java b/server/src/main/java/io/crate/types/EqQuery.java
index 8cca9c0883..5e446b888f 100644
--- a/server/src/main/java/io/crate/types/EqQuery.java
+++ b/server/src/main/java/io/crate/types/EqQuery.java
@@ -23,17 +23,20 @@ package io.crate.types;
 
 import org.apache.lucene.search.Query;
 
+import io.crate.metadata.IndexType;
+
 /**
  * For types which can be stored in Lucene and support optimized equality related queries
  **/
 public interface EqQuery<T> {
 
-    Query termQuery(String field, T value);
+    Query termQuery(String field, T value, boolean hasDocValues, IndexType indexType);
 
     Query rangeQuery(String field,
                      T lowerTerm,
                      T upperTerm,
                      boolean includeLower,
                      boolean includeUpper,
-                     boolean hasDocValues);
+                     boolean hasDocValues,
+                     IndexType indexType);
 }
diff --git a/server/src/main/java/io/crate/types/FloatType.java b/server/src/main/java/io/crate/types/FloatType.java
index c91ece1ca5..c8acb0c7fd 100644
--- a/server/src/main/java/io/crate/types/FloatType.java
+++ b/server/src/main/java/io/crate/types/FloatType.java
@@ -27,9 +27,9 @@ import java.math.BigInteger;
 import java.util.function.Function;
 
 import org.apache.lucene.document.FieldType;
+import org.apache.lucene.document.FloatField;
 import org.apache.lucene.document.FloatPoint;
 import org.apache.lucene.document.SortedNumericDocValuesField;
-import org.apache.lucene.search.IndexOrDocValuesQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.util.NumericUtils;
 import org.apache.lucene.util.RamUsageEstimator;
@@ -40,6 +40,7 @@ import io.crate.Streamer;
 import io.crate.execution.dml.FloatIndexer;
 import io.crate.execution.dml.ValueIndexer;
 import io.crate.metadata.ColumnIdent;
+import io.crate.metadata.IndexType;
 import io.crate.metadata.Reference;
 import io.crate.metadata.RelationName;
 
@@ -55,8 +56,16 @@ public class FloatType extends DataType<Float> implements Streamer<Float>, Fixed
         new EqQuery<Float>() {
 
             @Override
-            public Query termQuery(String field, Float value) {
-                return FloatPoint.newExactQuery(field, value);
+            public Query termQuery(String field, Float value, boolean hasDocValues, IndexType indexType) {
+                boolean isIndexed = indexType != IndexType.NONE;
+                if (hasDocValues && isIndexed) {
+                    return FloatField.newExactQuery(field, value);
+                } else if (hasDocValues) {
+                    return SortedNumericDocValuesField.newSlowExactQuery(field, NumericUtils.floatToSortableInt(value));
+                } else if (isIndexed) {
+                    return FloatPoint.newExactQuery(field, value);
+                }
+                return null;
             }
 
             @Override
@@ -65,7 +74,8 @@ public class FloatType extends DataType<Float> implements Streamer<Float>, Fixed
                                     Float upperTerm,
                                     boolean includeLower,
                                     boolean includeUpper,
-                                    boolean hasDocValues) {
+                                    boolean hasDocValues,
+                                    IndexType indexType) {
                 float lower;
                 if (lowerTerm == null) {
                     lower = Float.NEGATIVE_INFINITY;
@@ -79,16 +89,18 @@ public class FloatType extends DataType<Float> implements Streamer<Float>, Fixed
                 } else {
                     upper = includeUpper ? upperTerm : FloatPoint.nextDown(upperTerm);
                 }
-
-                Query indexQuery = FloatPoint.newRangeQuery(field, lower, upper);
-                if (hasDocValues) {
-                    Query dvQuery = SortedNumericDocValuesField
-                            .newSlowRangeQuery(field,
-                                               NumericUtils.floatToSortableInt(lower),
-                                               NumericUtils.floatToSortableInt(upper));
-                    return new IndexOrDocValuesQuery(indexQuery, dvQuery);
+                boolean isIndexed = indexType != IndexType.NONE;
+                if (hasDocValues && isIndexed) {
+                    return FloatField.newRangeQuery(field, lower, upper);
+                } else if (hasDocValues) {
+                    return SortedNumericDocValuesField.newSlowRangeQuery(
+                        field,
+                        NumericUtils.floatToSortableInt(lower),
+                        NumericUtils.floatToSortableInt(upper));
+                } else if (isIndexed) {
+                    return FloatPoint.newRangeQuery(field, lower, upper);
                 }
-                return indexQuery;
+                return null;
             }
         }
     ) {
diff --git a/server/src/main/java/io/crate/types/FloatVectorType.java b/server/src/main/java/io/crate/types/FloatVectorType.java
index e8005f0b49..6179bab481 100644
--- a/server/src/main/java/io/crate/types/FloatVectorType.java
+++ b/server/src/main/java/io/crate/types/FloatVectorType.java
@@ -40,6 +40,7 @@ import io.crate.Streamer;
 import io.crate.execution.dml.FloatVectorIndexer;
 import io.crate.execution.dml.ValueIndexer;
 import io.crate.metadata.ColumnIdent;
+import io.crate.metadata.IndexType;
 import io.crate.metadata.Reference;
 import io.crate.metadata.RelationName;
 import io.crate.sql.tree.ColumnDefinition;
@@ -57,7 +58,7 @@ public class FloatVectorType extends DataType<float[]> implements Streamer<float
     private static final EqQuery<float[]> EQ_QUERY = new EqQuery<float[]>() {
 
         @Override
-        public Query termQuery(String field, float[] value) {
+        public Query termQuery(String field, float[] value, boolean hasDocValues, IndexType indexType) {
             return null;
         }
 
@@ -67,7 +68,8 @@ public class FloatVectorType extends DataType<float[]> implements Streamer<float
                                 float[] upperTerm,
                                 boolean includeLower,
                                 boolean includeUpper,
-                                boolean hasDocValues) {
+                                boolean hasDocValues,
+                                IndexType indexType) {
             return null;
         }
     };
diff --git a/server/src/main/java/io/crate/types/IntEqQuery.java b/server/src/main/java/io/crate/types/IntEqQuery.java
index 834aa49db3..585430857f 100644
--- a/server/src/main/java/io/crate/types/IntEqQuery.java
+++ b/server/src/main/java/io/crate/types/IntEqQuery.java
@@ -21,16 +21,26 @@
 
 package io.crate.types;
 
+import org.apache.lucene.document.IntField;
 import org.apache.lucene.document.IntPoint;
 import org.apache.lucene.document.SortedNumericDocValuesField;
-import org.apache.lucene.search.IndexOrDocValuesQuery;
 import org.apache.lucene.search.Query;
 
+import io.crate.metadata.IndexType;
+
 public class IntEqQuery implements EqQuery<Number> {
 
     @Override
-    public Query termQuery(String field, Number value) {
-        return IntPoint.newExactQuery(field, value.intValue());
+    public Query termQuery(String field, Number value, boolean hasDocValues, IndexType indexType) {
+        boolean isIndexed = indexType != IndexType.NONE;
+        if (hasDocValues && isIndexed) {
+            return IntField.newExactQuery(field, value.intValue());
+        } else if (hasDocValues) {
+            return SortedNumericDocValuesField.newSlowExactQuery(field, value.intValue());
+        } else if (isIndexed) {
+            return IntPoint.newExactQuery(field, value.intValue());
+        }
+        return null;
     }
 
     @Override
@@ -39,7 +49,8 @@ public class IntEqQuery implements EqQuery<Number> {
                             Number upperTerm,
                             boolean includeLower,
                             boolean includeUpper,
-                            boolean hasDocValues) {
+                            boolean hasDocValues,
+                            IndexType indexType) {
         int lower = Integer.MIN_VALUE;
         if (lowerTerm != null) {
             lower = includeLower ? lowerTerm.intValue() : lowerTerm.intValue() + 1;
@@ -48,11 +59,14 @@ public class IntEqQuery implements EqQuery<Number> {
         if (upperTerm != null) {
             upper = includeUpper ? upperTerm.intValue() : upperTerm.intValue() - 1;
         }
-        Query indexquery = IntPoint.newRangeQuery(field, lower, upper);
-        if (hasDocValues) {
-            return new IndexOrDocValuesQuery(
-                    indexquery, SortedNumericDocValuesField.newSlowRangeQuery(field, lower, upper));
+        boolean isIndexed = indexType != IndexType.NONE;
+        if (hasDocValues && isIndexed) {
+            return IntField.newRangeQuery(field, lower, upper);
+        } else if (hasDocValues) {
+            return SortedNumericDocValuesField.newSlowRangeQuery(field, lower, upper);
+        } else if (isIndexed) {
+            return IntPoint.newRangeQuery(field, lower, upper);
         }
-        return indexquery;
+        return null;
     }
 }
diff --git a/server/src/main/java/io/crate/types/IpType.java b/server/src/main/java/io/crate/types/IpType.java
index eafca8ef2f..d40534a7c9 100644
--- a/server/src/main/java/io/crate/types/IpType.java
+++ b/server/src/main/java/io/crate/types/IpType.java
@@ -27,7 +27,10 @@ import java.util.function.Function;
 
 import org.apache.lucene.document.FieldType;
 import org.apache.lucene.document.InetAddressPoint;
+import org.apache.lucene.document.SortedSetDocValuesField;
+import org.apache.lucene.search.IndexOrDocValuesQuery;
 import org.apache.lucene.search.Query;
+import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.RamUsageEstimator;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
@@ -37,6 +40,7 @@ import io.crate.Streamer;
 import io.crate.execution.dml.IpIndexer;
 import io.crate.execution.dml.ValueIndexer;
 import io.crate.metadata.ColumnIdent;
+import io.crate.metadata.IndexType;
 import io.crate.metadata.Reference;
 import io.crate.metadata.RelationName;
 
@@ -51,8 +55,19 @@ public class IpType extends DataType<String> implements Streamer<String> {
         new EqQuery<String>() {
 
             @Override
-            public Query termQuery(String field, String value) {
-                return InetAddressPoint.newExactQuery(field, InetAddresses.forString(value));
+            public Query termQuery(String field, String value, boolean hasDocValues, IndexType indexType) {
+                boolean isIndexed = indexType != IndexType.NONE;
+                if (hasDocValues && isIndexed) {
+                    return new IndexOrDocValuesQuery(
+                        InetAddressPoint.newExactQuery(field, InetAddresses.forString(value)),
+                        SortedSetDocValuesField.newSlowExactQuery(field, new BytesRef(InetAddressPoint.encode(InetAddresses.forString(value))))
+                    );
+                } else if (hasDocValues) {
+                    return SortedSetDocValuesField.newSlowExactQuery(field, new BytesRef(InetAddressPoint.encode(InetAddresses.forString(value))));
+                } else if (isIndexed) {
+                    return InetAddressPoint.newExactQuery(field, InetAddresses.forString(value));
+                }
+                return null;
             }
 
             @Override
@@ -61,7 +76,8 @@ public class IpType extends DataType<String> implements Streamer<String> {
                                     String upperTerm,
                                     boolean includeLower,
                                     boolean includeUpper,
-                                    boolean hasDocValues) {
+                                    boolean hasDocValues,
+                                    IndexType indexType) {
                 InetAddress lower;
                 if (lowerTerm == null) {
                     lower = InetAddressPoint.MIN_VALUE;
@@ -69,6 +85,7 @@ public class IpType extends DataType<String> implements Streamer<String> {
                     var lowerAddress = InetAddresses.forString(lowerTerm);
                     lower = includeLower ? lowerAddress : InetAddressPoint.nextUp(lowerAddress);
                 }
+                includeLower = true; // lowerAddress has been adjusted
 
                 InetAddress upper;
                 if (upperTerm == null) {
@@ -77,8 +94,29 @@ public class IpType extends DataType<String> implements Streamer<String> {
                     var upperAddress = InetAddresses.forString(upperTerm);
                     upper = includeUpper ? upperAddress : InetAddressPoint.nextDown(upperAddress);
                 }
-
-                return InetAddressPoint.newRangeQuery(field, lower, upper);
+                includeUpper = true; // upperAddress has been adjusted
+
+                boolean isIndexed = indexType != IndexType.NONE;
+                if (hasDocValues && isIndexed) {
+                    return new IndexOrDocValuesQuery(
+                        InetAddressPoint.newRangeQuery(field, lower, upper),
+                        SortedSetDocValuesField.newSlowRangeQuery(
+                            field,
+                            new BytesRef(InetAddressPoint.encode(lower)),
+                            new BytesRef(InetAddressPoint.encode(upper)),
+                            includeLower,
+                            includeUpper));
+                } else if (hasDocValues) {
+                    return SortedSetDocValuesField.newSlowRangeQuery(
+                        field,
+                        new BytesRef(InetAddressPoint.encode(lower)),
+                        new BytesRef(InetAddressPoint.encode(upper)),
+                        includeLower,
+                        includeUpper);
+                } else if (isIndexed) {
+                    return InetAddressPoint.newRangeQuery(field, lower, upper);
+                }
+                return null;
             }
         }
     ) {
diff --git a/server/src/main/java/io/crate/types/LongEqQuery.java b/server/src/main/java/io/crate/types/LongEqQuery.java
index 83904b5880..bc690f12aa 100644
--- a/server/src/main/java/io/crate/types/LongEqQuery.java
+++ b/server/src/main/java/io/crate/types/LongEqQuery.java
@@ -21,16 +21,26 @@
 
 package io.crate.types;
 
+import org.apache.lucene.document.LongField;
 import org.apache.lucene.document.LongPoint;
 import org.apache.lucene.document.SortedNumericDocValuesField;
-import org.apache.lucene.search.IndexOrDocValuesQuery;
 import org.apache.lucene.search.Query;
 
+import io.crate.metadata.IndexType;
+
 public class LongEqQuery implements EqQuery<Long> {
 
     @Override
-    public Query termQuery(String field, Long value) {
-        return LongPoint.newExactQuery(field, value);
+    public Query termQuery(String field, Long value, boolean hasDocValues, IndexType indexType) {
+        boolean isIndexed = indexType != IndexType.NONE;
+        if (hasDocValues && isIndexed) {
+            return LongField.newExactQuery(field, value);
+        } else if (hasDocValues) {
+            return SortedNumericDocValuesField.newSlowExactQuery(field, value);
+        } else if (isIndexed) {
+            return LongPoint.newExactQuery(field, value);
+        }
+        return null;
     }
 
     @Override
@@ -39,18 +49,22 @@ public class LongEqQuery implements EqQuery<Long> {
                             Long upperTerm,
                             boolean includeLower,
                             boolean includeUpper,
-                            boolean hasDocValues) {
+                            boolean hasDocValues,
+                            IndexType indexType) {
         long lower = lowerTerm == null
             ? Long.MIN_VALUE
             : (includeLower ? lowerTerm : lowerTerm + 1);
         long upper = upperTerm == null
             ? Long.MAX_VALUE
             : (includeUpper ? upperTerm : upperTerm - 1);
-        Query indexQuery = LongPoint.newRangeQuery(field, lower, upper);
-        if (hasDocValues) {
-            return new IndexOrDocValuesQuery(indexQuery,
-                                             SortedNumericDocValuesField.newSlowRangeQuery(field, lower, upper));
+        boolean isIndexed = indexType != IndexType.NONE;
+        if (hasDocValues && isIndexed) {
+            return LongField.newRangeQuery(field, lower, upper);
+        } else if (hasDocValues) {
+            return SortedNumericDocValuesField.newSlowRangeQuery(field, lower, upper);
+        } else if (isIndexed) {
+            return LongPoint.newRangeQuery(field, lower, upper);
         }
-        return indexQuery;
+        return null;
     }
 }
diff --git a/server/src/main/java/io/crate/types/StringType.java b/server/src/main/java/io/crate/types/StringType.java
index 2c3ffde4b9..c510290a34 100644
--- a/server/src/main/java/io/crate/types/StringType.java
+++ b/server/src/main/java/io/crate/types/StringType.java
@@ -33,6 +33,7 @@ import java.util.Objects;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
+import org.apache.lucene.document.SortedSetDocValuesField;
 import org.jetbrains.annotations.Nullable;
 
 import org.apache.lucene.document.FieldType;
@@ -55,6 +56,7 @@ import io.crate.execution.dml.FulltextIndexer;
 import io.crate.execution.dml.StringIndexer;
 import io.crate.execution.dml.ValueIndexer;
 import io.crate.metadata.ColumnIdent;
+import io.crate.metadata.IndexType;
 import io.crate.metadata.Reference;
 import io.crate.metadata.RelationName;
 import io.crate.metadata.settings.SessionSettings;
@@ -78,8 +80,14 @@ public class StringType extends DataType<String> implements Streamer<String> {
         new EqQuery<Object>() {
 
             @Override
-            public Query termQuery(String field, Object value) {
-                return new TermQuery(new Term(field, BytesRefs.toBytesRef(value)));
+            public Query termQuery(String field, Object value, boolean hasDocValues, IndexType indexType) {
+                if (indexType == IndexType.PLAIN && hasDocValues) {
+                    return SortedSetDocValuesField.newSlowExactQuery(field, BytesRefs.toBytesRef(value));
+                } else if (indexType != IndexType.NONE) {
+                    return new TermQuery(new Term(field, BytesRefs.toBytesRef(value)));
+                } else {
+                    return null;
+                }
             }
 
             @Override
@@ -88,14 +96,27 @@ public class StringType extends DataType<String> implements Streamer<String> {
                                     Object upperTerm,
                                     boolean includeLower,
                                     boolean includeUpper,
-                                    boolean hasDocValues) {
-                return new TermRangeQuery(
-                    field,
-                    BytesRefs.toBytesRef(lowerTerm),
-                    BytesRefs.toBytesRef(upperTerm),
-                    includeLower,
-                    includeUpper
-                );
+                                    boolean hasDocValues,
+                                    IndexType indexType) {
+                if (indexType == IndexType.PLAIN && hasDocValues) {
+                    return SortedSetDocValuesField.newSlowRangeQuery(
+                        field,
+                        BytesRefs.toBytesRef(lowerTerm),
+                        BytesRefs.toBytesRef(upperTerm),
+                        includeLower,
+                        includeUpper
+                    );
+                } else if (indexType != null && upperTerm != null && lowerTerm != null) {
+                    return new TermRangeQuery(
+                        field,
+                        BytesRefs.toBytesRef(lowerTerm),
+                        BytesRefs.toBytesRef(upperTerm),
+                        includeLower,
+                        includeUpper
+                    );
+                } else {
+                    return null;
+                }
             }
         }
     ) {
diff --git a/server/src/test/java/io/crate/expression/operator/EqOperatorTest.java b/server/src/test/java/io/crate/expression/operator/EqOperatorTest.java
index 8e6ea65274..071e36ac2e 100644
--- a/server/src/test/java/io/crate/expression/operator/EqOperatorTest.java
+++ b/server/src/test/java/io/crate/expression/operator/EqOperatorTest.java
@@ -34,6 +34,7 @@ import org.junit.Test;
 
 import io.crate.expression.scalar.ScalarTestCase;
 import io.crate.lucene.GenericFunctionQuery;
+import io.crate.metadata.IndexType;
 import io.crate.metadata.doc.DocSysColumns;
 import io.crate.testing.Asserts;
 import io.crate.testing.DataTypeTesting;
@@ -141,7 +142,17 @@ public class EqOperatorTest extends ScalarTestCase {
 
     @Test
     public void test_terms_query_on__id_encodes_ids() throws Exception {
-        Query query = EqOperator.termsQuery(DocSysColumns.ID.name(), DataTypes.STRING, List.of("foo", "bar"));
+        Query query = EqOperator.termsQuery(DocSysColumns.ID.name(), DataTypes.STRING, List.of("foo", "bar"), true, IndexType.FULLTEXT);
+        assertThat(query).hasToString("_id:([7e 8a] [ff 62 61 72])");
+        query = EqOperator.termsQuery(DocSysColumns.ID.name(), DataTypes.STRING, List.of("foo", "bar"), true, IndexType.PLAIN);
+        assertThat(query).hasToString("_id:([7e 8a] [ff 62 61 72])");
+        query = EqOperator.termsQuery(DocSysColumns.ID.name(), DataTypes.STRING, List.of("foo", "bar"), true, IndexType.NONE);
+        assertThat(query).hasToString("_id:([7e 8a] [ff 62 61 72])");
+        query = EqOperator.termsQuery(DocSysColumns.ID.name(), DataTypes.STRING, List.of("foo", "bar"), false, IndexType.FULLTEXT);
+        assertThat(query).hasToString("_id:([7e 8a] [ff 62 61 72])");
+        query = EqOperator.termsQuery(DocSysColumns.ID.name(), DataTypes.STRING, List.of("foo", "bar"), false, IndexType.PLAIN);
+        assertThat(query).hasToString("_id:([7e 8a] [ff 62 61 72])");
+        query = EqOperator.termsQuery(DocSysColumns.ID.name(), DataTypes.STRING, List.of("foo", "bar"), false, IndexType.NONE);
         assertThat(query).hasToString("_id:([7e 8a] [ff 62 61 72])");
     }
 
diff --git a/server/src/test/java/io/crate/integrationtests/DDLIntegrationTest.java b/server/src/test/java/io/crate/integrationtests/DDLIntegrationTest.java
index 3ebc9f3681..44eca5c7af 100644
--- a/server/src/test/java/io/crate/integrationtests/DDLIntegrationTest.java
+++ b/server/src/test/java/io/crate/integrationtests/DDLIntegrationTest.java
@@ -30,7 +30,6 @@ import static io.crate.testing.TestingHelpers.printedTable;
 import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
 import static io.netty.handler.codec.http.HttpResponseStatus.CONFLICT;
 import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
-import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertEquals;
 
 import java.util.ArrayList;
@@ -292,11 +291,8 @@ public class DDLIntegrationTest extends IntegTestCase {
         String quote = "Would it save you a lot of time if I just gave up and went mad now?";
         execute("insert into quotes (id, quote) values (?, ?)", new Object[]{1, quote});
         execute("refresh table quotes");
-
-        Asserts.assertSQLError(() -> execute("select quote from quotes where quote = ?", new Object[]{quote}))
-            .hasPGError(INTERNAL_ERROR)
-            .hasHTTPError(BAD_REQUEST, 4000)
-            .hasMessageContaining("Cannot search on field [quote] since it is not indexed.");
+        execute("select quote from quotes where quote = ?", new Object[]{quote});
+        assertThat(response).hasRows(quote);
     }
 
     @Test
diff --git a/server/src/test/java/io/crate/integrationtests/LuceneQueryBuilderIntegrationTest.java b/server/src/test/java/io/crate/integrationtests/LuceneQueryBuilderIntegrationTest.java
index ef5696752a..f11410a99a 100644
--- a/server/src/test/java/io/crate/integrationtests/LuceneQueryBuilderIntegrationTest.java
+++ b/server/src/test/java/io/crate/integrationtests/LuceneQueryBuilderIntegrationTest.java
@@ -36,6 +36,7 @@ import org.elasticsearch.test.IntegTestCase;
 import org.junit.Test;
 
 import io.crate.testing.DataTypeTesting;
+import io.crate.testing.UseJdbc;
 import io.crate.testing.UseRandomizedOptimizerRules;
 import io.crate.types.DataType;
 
@@ -425,4 +426,192 @@ public class LuceneQueryBuilderIntegrationTest extends IntegTestCase {
             .as("query doesn't match")
             .hasRowCount(0L);
     }
+
+    @UseJdbc(0)
+    @Test
+    public void test_eq_queries_with_index_on_and_column_store_true() {
+        execute(
+            """
+                    create table t (
+                        a bit(2),
+                        b double,
+                        c float,
+                        d ip,
+                        e string,
+                        f boolean,
+                        g int,
+                        h long,
+                        i string index using fulltext
+                    )
+                """
+        );
+        String firstRow = "(B'01', 1.1, 1.1, '1.1.1.1', 'a', false, 1, 1, 'a')";
+        String expectedFirstRow = "B'01'| 1.1| 1.1| 1.1.1.1| a| false| 1| 1| a";
+        String secondRow = "(B'10', 1.2, 1.2, '1.1.1.2', 'b', true,  2, 2, 'b')";
+        String expectedSecondRow = "B'10'| 1.2| 1.2| 1.1.1.2| b| true| 2| 2| b";
+        execute("insert into t values " + firstRow + ", " + secondRow);
+        refresh();
+
+        // EqQuery.termQuery
+        assertThat(execute("select * from t where a = B'01'")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where b = 1.1")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where c = 1.1")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where d = '1.1.1.1'")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where e = 'a'")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where f = false")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where g = 1")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where h = 1")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where i = 'a'")).hasRows(expectedFirstRow);
+
+        // EqQuery.RangeQuery
+        //UnsupportedFunctionException: Unknown function: (mgjihphcgyjgklnrovd.t.a > B'01'), no overload found for matching argument types: (bit, bit). Possible candidates: op_>(byte, byte):boolean, op_>(boolean, boolean):boolean, op_>(character, character):boolean, op_>(text, text):boolean, op_>(ip, ip):boolean, op_>(double precision, double precision):boolean, op_>(real, real):boolean, op_>(smallint, smallint):boolean, op_>(integer, integer):boolean, op_>(interval, interval):boolean, op_>(bigint, bigint):boolean, op_>(timestamp with time zone, timestamp with time zone):boolean, op_>(timestamp without time zone, timestamp without time zone):boolean, op_>(date, date):boolean
+        //assertThat(execute("select * from t where a > B'01'")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where b > 1.1")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where c > 1.1")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where d > '1.1.1.1'")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where e > 'a'")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where f > false")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where g > 1")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where h > 1")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where i > 'a'")).hasRows(expectedSecondRow);
+    }
+
+    @UseJdbc(0)
+    @Test
+    public void test_eq_queries_with_index_off_and_column_store_true() {
+        execute(
+            """
+                    create table t (
+                        a bit(2) index off,
+                        b double index off,
+                        c float index off,
+                        d ip index off,
+                        e string index off,
+                        f boolean index off,
+                        g int index off,
+                        h long index off
+                    )
+                """
+        );
+        String firstRow = "(B'01', 1.1, 1.1, '1.1.1.1', 'a', false, 1, 1)";
+        String expectedFirstRow = "B'01'| 1.1| 1.1| 1.1.1.1| a| false| 1| 1";
+        String secondRow = "(B'10', 1.2, 1.2, '1.1.1.2', 'b', true,  2, 2)";
+        String expectedSecondRow = "B'10'| 1.2| 1.2| 1.1.1.2| b| true| 2| 2";
+        execute("insert into t values " + firstRow + ", " + secondRow);
+        refresh();
+
+        // EqQuery.termQuery
+        assertThat(execute("select * from t where a = B'01'")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where b = 1.1")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where c = 1.1")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where d = '1.1.1.1'")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where e = 'a'")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where f = false")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where g = 1")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where h = 1")).hasRows(expectedFirstRow);
+
+        // EqQuery.RangeQuery
+        // UnsupportedFunctionException: Unknown function
+        //assertThat(execute("select * from t where a > B'01'")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where b > 1.1")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where c > 1.1")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where d > '1.1.1.1'")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where e > 'a'")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where f > false")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where g > 1")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where h > 1")).hasRows(expectedSecondRow);
+    }
+
+    @UseJdbc(0)
+    @Test
+    public void test_eq_queries_with_index_off_and_column_store_false() {
+        execute(
+            """
+                    create table t (
+                        a bit(2) index off,
+                        b double index off storage with (columnstore=false),
+                        c float index off storage with (columnstore=false),
+                        d ip index off,
+                        e string index off storage with (columnstore=false),
+                        f boolean index off,
+                        g int index off storage with (columnstore=false),
+                        h long index off storage with (columnstore=false)
+                    )
+                """
+        );
+        String firstRow = "(B'01', 1.1, 1.1, '1.1.1.1', 'a', false, 1, 1)";
+        String expectedFirstRow = "B'01'| 1.1| 1.1| 1.1.1.1| a| false| 1| 1";
+        String secondRow = "(B'10', 1.2, 1.2, '1.1.1.2', 'b', true,  2, 2)";
+        String expectedSecondRow = "B'10'| 1.2| 1.2| 1.1.1.2| b| true| 2| 2";
+        execute("insert into t values " + firstRow + ", " + secondRow);
+        refresh();
+
+        // EqQuery.termQuery
+        assertThat(execute("select * from t where a = B'01'")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where b = 1.1")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where c = 1.1")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where d = '1.1.1.1'")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where e = 'a'")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where f = false")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where g = 1")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where h = 1")).hasRows(expectedFirstRow);
+
+        // EqQuery.RangeQuery
+        //assertThat(execute("select * from t where a > B'01'")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where b > 1.1")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where c > 1.1")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where d > '1.1.1.1'")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where e > 'a'")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where f > false")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where g > 1")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where h > 1")).hasRows(expectedSecondRow);
+    }
+
+    @UseJdbc(0)
+    @Test
+    public void test_eq_queries_with_index_on_and_column_store_false() {
+        execute(
+            """
+                    create table t (
+                        a bit(2),
+                        b double storage with (columnstore=false),
+                        c float storage with (columnstore=false),
+                        d ip,
+                        e string storage with (columnstore=false),
+                        f boolean,
+                        g int storage with (columnstore=false),
+                        h long storage with (columnstore=false),
+                        i text index using fulltext storage with (columnstore=false)
+                    )
+                """
+        );
+        String firstRow = "(B'01', 1.1, 1.1, '1.1.1.1', 'a', false, 1, 1, 'a')";
+        String expectedFirstRow = "B'01'| 1.1| 1.1| 1.1.1.1| a| false| 1| 1| a";
+        String secondRow = "(B'10', 1.2, 1.2, '1.1.1.2', 'b', true,  2, 2, 'b')";
+        String expectedSecondRow = "B'10'| 1.2| 1.2| 1.1.1.2| b| true| 2| 2| b";
+        execute("insert into t values " + firstRow + ", " + secondRow);
+        refresh();
+
+        // EqQuery.termQuery
+        assertThat(execute("select * from t where a = B'01'")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where b = 1.1")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where c = 1.1")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where d = '1.1.1.1'")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where e = 'a'")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where f = false")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where g = 1")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where h = 1")).hasRows(expectedFirstRow);
+        assertThat(execute("select * from t where i = 'a'")).hasRows(expectedFirstRow);
+
+        // EqQuery.RangeQuery
+        //assertThat(execute("select * from t where a > B'01'")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where b > 1.1")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where c > 1.1")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where d > '1.1.1.1'")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where e > 'a'")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where f > false")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where g > 1")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where h > 1")).hasRows(expectedSecondRow);
+        assertThat(execute("select * from t where i > 'a'")).hasRows(expectedSecondRow);
+    }
 }