Skip to content

fix(pgwire): improve support for bind variables as function arguments#5999

Merged
bluestreak01 merged 54 commits intomasterfrom
vi_pg_arr_fix
Sep 30, 2025
Merged

fix(pgwire): improve support for bind variables as function arguments#5999
bluestreak01 merged 54 commits intomasterfrom
vi_pg_arr_fix

Conversation

@bluestreak01
Copy link
Copy Markdown
Member

@bluestreak01 bluestreak01 commented Jul 29, 2025

Fixes issues passing bind variables into function calls, such as

select array_position($1, field) from tab

Multiple symptoms:

  • bind variables would be defined typeless Array on the server, requiring explicit $1::float8[] cast in the SQL
  • passing unsupported types would either lead to unexpected successes, such as inserting "int8" typed array into "double[]" field or wacky errors, such as passing int8[] into array_position($1, field) would yield "expected DOUBLE but found ARRAY in parameter 1". This is completely confusing for the user and diverges from the documentation.
  • unsupported types would default to STRING, such as binary representation of INTERVAL type. This would lead to deterministic behaviour
  • function with ARRAY arguments will not define its type to PG drivers that require such behaviour, such as tokio-postgres. The result would be complete impossibility of using bind variables with functions that have array args, even if bind variable is used for scalar parameters. The error would be something like "cannot convert UNKNOW to DOUBLE[]"

Tested using AI with Rust:

  • sqlx - server side type validation
  • tokip-postgres - client side type validation

Changes:

  • server would correctly reject incompatible type, e.g. "expected DOUBLE[] but got LONG[]"
  • server will correctly reject unsupported types, such as INTERVAL, INET, their arrays and many other types.
  • function parser will treat UNDEFINED type such that it would define type for the best matching function signature. This results in tokio-postgres being able to use bind variables.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Aug 1, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Adds weak-dimensional array encoding and APIs in ColumnType; propagates weak-dims support and stricter dimensionality validation across array parsing, functions, casts, and PG wire binding; expands PostgreSQL OID mappings and PG bind handling; updates tests and compatibility runners for new array behavior and OIDs.

Changes

Cohort / File(s) Summary
Core: ColumnType & array API
core/src/main/java/io/questdb/cairo/ColumnType.java, core/src/test/java/io/questdb/test/cairo/ColumnTypeTest.java
Add TYPE_FLAG_ARRAY_WEAK_DIMS; decodeArrayDimensionality returns -1 for weak dims; new public APIs: encodeArrayType(..., boolean), encodeArrayTypeWithWeakDims, isArrayWithWeakDims; precompute/register array type names; unit test added.
Core: PG OIDs & bind handling
core/src/main/java/io/questdb/cutlass/pgwire/PGOids.java, core/src/main/java/io/questdb/cutlass/pgwire/PGPipelineEntry.java
Add many PG_ARR_*, PG_*, and X_PG_* constants; extend scalar→array OID mapping; bind new array OIDs via ColumnType.encodeArrayTypeWithWeakDims(...); explicit CairoException for unsupported PG types.
Core: Array functions, casts, and parsers
core/src/main/java/io/questdb/griffin/engine/functions/array/**, core/src/main/java/io/questdb/griffin/engine/functions/cast/**, core/src/main/java/io/questdb/griffin/FunctionParser.java, core/src/main/java/io/questdb/griffin/SqlCodeGenerator.java, core/src/main/java/io/questdb/griffin/SqlUtil.java
Widespread changes to support weak/unknown dims: many factories add init(SymbolTableSource,...) for runtime dim resolution, introduce WeakDimsFunc for casts, tighten dimensionality validation and error positions, treat undefined array args as fuzzy matches in overload resolution, and make getUnionCastType throw SqlException.
Core: Bind variables & runtime array binds
core/src/main/java/io/questdb/griffin/engine/functions/bind/ArrayBindVariable.java
Use local type field, switch isUnderdefined→isUndefined, stricter parse/setView handling and error formatting; clear resets local type to UNDEFINED.
Core: Array runtime drivers / memory views
core/src/main/java/io/questdb/cairo/arr/* (ArrayTypeDriver.java, BorrowedArray.java, MutableArray.java)
Local variable renames to dims, add assert dims > 0 in several places (activates when JVM assertions enabled); no public signature changes.
Core: Line TCP & binary formats
core/src/main/java/io/questdb/cutlass/line/tcp/ArrayBinaryFormatParser.java, core/src/main/java/io/questdb/cutlass/line/tcp/LineTcpEventBuffer.java
Read nDims as unsigned byte; add runtime validation rejecting dims <1 or > limit and throw CairoException on unsupported dimensionality.
Core: Utilities, codegen & constants
core/src/main/java/io/questdb/griffin/RecordToRowCopierUtils.java, core/src/main/java/io/questdb/griffin/engine/functions/constants/**, core/src/main/java/io/questdb/griffin/SqlCodeGenerator.java
Add @SuppressWarnings for generated-use methods; assert dims>0 in constants; getUnionCastType now throws SqlException; adjust array-dim handling in several helpers.
Core: PG array tests & other tests
core/src/test/java/io/questdb/test/cutlass/pgwire/PGArraysTest.java, core/src/test/java/io/questdb/test/cutlass/pgwire/PGJobContextTest.java, core/src/test/java/io/questdb/test/griffin/*, core/src/test/java/io/questdb/test/cairo/*
Update tests to use float8 arrays, adjust expected OIDs and error messages/positions, add tests for array bind edge cases and 2D array JDBC bind; add ColumnTypeTest.
Compat tests, Rust runner & CI
.github/workflows/pgwire_stable.yml, .gitignore, compat/src/test/resources/test_cases.yaml, compat/src/test/rust-sqlx/*, compat/src/test/scenarios_*.sh
Add rust-sqlx test runner (crate, Cargo.unlocked, main.rs), new YAML test cases focused on arrays, split/rename rust-tokio scripts, update CI Rust toolchain, adjust .gitignore entries.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant PGWire
  participant PGPipelineEntry
  participant ColumnType

  Client->>PGWire: Send bind param (array OID)
  PGWire->>PGPipelineEntry: defineBindVariableType(oid)
  PGPipelineEntry->>ColumnType: encodeArrayTypeWithWeakDims(baseType, false)
  ColumnType-->>PGPipelineEntry: encoded array type (weak dims)
  PGPipelineEntry-->>PGWire: bound type or error
  PGWire-->>Client: bind accepted / error
Loading
sequenceDiagram
  participant Parser
  participant FunctionResolver
  participant ColumnType

  Parser->>FunctionResolver: resolve(function, argTypes)
  alt param expects array
    FunctionResolver->>ColumnType: decodeArrayElementType / decodeArrayDimensionality
    ColumnType-->>FunctionResolver: elementType, nDims (or -1 for weak)
    FunctionResolver->>Parser: pick overload or report array-aware error
  else normal param
    FunctionResolver->>Parser: pick overload
  end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested labels

Bug, Java, SQL

Suggested reviewers

  • ideoma

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.55% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly and accurately describes the primary intent of the changeset: improving pgwire handling of bind variables used as function arguments. It names the affected subsystem (pgwire) and is specific enough for a reviewer scanning history to understand the PR’s focus without noisy details. The wording is concise and directly aligns with the changes in ColumnType, PGOids, PGPipelineEntry, and FunctionParser described in the diff.
Description Check ✅ Passed The description clearly explains the problem being fixed (bind-variable typing for function arguments), enumerates observed symptoms, summarizes the implemented fixes and tests, and lists key files changed; this matches the provided raw_summary and PR objectives. Level of detail is sufficient for reviewers to understand intent, scope, and testing performed without being off-topic. The description is directly related to the changeset and therefore meets the lenient acceptance criteria.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🧪 Early access (Sonnet 4.5): enabled

We are currently testing the Sonnet 4.5 model, which is expected to improve code review quality. However, this model may lead to increased noise levels in the review comments. Please disable the early access features if the noise level causes any inconvenience.

Note:

  • Public repositories are always opted into early access features.
  • You can enable or disable early access features from the CodeRabbit UI or by updating the CodeRabbit configuration file.

Comment @coderabbitai help to get the list of available commands and usage tips.

@bluestreak01
Copy link
Copy Markdown
Member Author

@CodeRabbit please review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Aug 14, 2025

🧩 Analysis chain

I'll review the changes for you. Let me examine the modified files to understand the implementation details.


🏁 Script executed:

#!/bin/bash
# Get the list of changed files and examine the diff
git diff --name-only HEAD~1 HEAD

# Show the changes in each of the modified files
echo "=== Changes in PGPipelineEntry.java ==="
git diff HEAD~1 HEAD -- io/questdb/cutlass/pgwire/modern/PGPipelineEntry.java

echo -e "\n=== Changes in FunctionParser.java ==="
git diff HEAD~1 HEAD -- io/questdb/griffin/FunctionParser.java

echo -e "\n=== Changes in PGOids.java ==="
git diff HEAD~1 HEAD -- io/questdb/cutlass/pgwire/PGOids.java

echo -e "\n=== Changes in ColumnType.java ==="
git diff HEAD~1 HEAD -- io/questdb/cairo/ColumnType.java

Length of output: 949


Let me check the git status and examine the files directly to understand the changes:


🏁 Script executed:

#!/bin/bash
# Check git status and branch information
git status
git branch -a
git log --oneline -5

# If that doesn't work, let's examine the files directly
echo -e "\n=== Examining PGPipelineEntry.java ==="
cat io/questdb/cutlass/pgwire/modern/PGPipelineEntry.java

echo -e "\n=== Examining FunctionParser.java ==="
cat io/questdb/griffin/FunctionParser.java

echo -e "\n=== Examining PGOids.java ==="
cat io/questdb/cutlass/pgwire/PGOids.java

echo -e "\n=== Examining ColumnType.java ==="
cat io/questdb/cairo/ColumnType.java

Length of output: 1022


Let me find the correct paths for these files and examine them:


🏁 Script executed:

#!/bin/bash
# Find the actual locations of the modified files
echo "=== Finding file locations ==="
fd -t f "PGPipelineEntry.java"
fd -t f "FunctionParser.java"
fd -t f "PGOids.java"
fd -t f "ColumnType.java"

# Get git log to understand the recent changes
echo -e "\n=== Recent commits ==="
git log --oneline -10

# Look for Java files in the repository structure
echo -e "\n=== Java files structure ==="
fd -e java | head -20

Length of output: 1768


Now let me examine the actual files to understand the implementation:


🏁 Script executed:

#!/bin/bash
echo "=== PGPipelineEntry.java ==="
cat core/src/main/java/io/questdb/cutlass/pgwire/PGPipelineEntry.java

echo -e "\n\n=== FunctionParser.java ==="
cat core/src/main/java/io/questdb/griffin/FunctionParser.java

echo -e "\n\n=== PGOids.java ==="
cat core/src/main/java/io/questdb/cutlass/pgwire/PGOids.java

echo -e "\n\n=== ColumnType.java ==="
cat core/src/main/java/io/questdb/cairo/ColumnType.java

Length of output: 266260


@bluestreak01 I'll review the changes that improve bind variable support as function arguments in pgwire. Let me examine the implementation across the four modified files.

Overall Assessment

This is a well-structured improvement to bind variable handling in PostgreSQL wire protocol functions. The changes address multiple pain points around type inference, validation, and client compatibility.

Key Improvements

1. Enhanced Type Resolution (FunctionParser.java)

The function parser now properly handles UNDEFINED types for bind variables, allowing the compiler to infer the best matching function signature:

// resolve previously UNDEFINED function types
for (int i = 0, n = undefinedVariables.size(); i < n; i++) {
    final int pos = undefinedVariables.getQuick(i);
    if (pos < candidateSigArgCount) {
        // assign arguments based on the candidate function descriptor
        int t = candidateDescriptor.getArgTypeWithFlags(pos);
        final short sigArgType = FunctionFactoryDescriptor.toTypeTag(t);
        final int argType;
        if (FunctionFactoryDescriptor.isArray(t)) {
            argType = ColumnType.encodeArrayType(sigArgType, 1);
        } else {
            argType = sigArgType;
        }
        args.getQuick(pos).assignType(argType, sqlExecutionContext.getBindVariableService());
    }
}

2. Improved PostgreSQL Type Mapping (PGOids.java)

New array type support and better OID handling:

public static int pgArrayToElementType(int pgOid) {
    switch (pgOid) {
        case PG_ARR_FLOAT8:
            return PG_FLOAT8;
        case PG_ARR_INT8:
            return PG_INT8;
        default:
            return 0;
    }
}

3. Better Error Messages (PGPipelineEntry.java)

The implementation now provides clearer error messages for type mismatches:

case X_PG_NUMERIC:
    throw CairoException.nonCritical().put("unsupported bind variable type NUMERIC (OID ").put(PG_NUMERIC).put(')');
case X_PG_ARR_NUMERIC:
    throw CairoException.nonCritical().put("unsupported bind variable type NUMERIC[] (OID ").put(PG_ARR_NUMERIC).put(')');

Areas of Concern

1. Array Support Limitation

The array support is currently limited to DOUBLE and LONG arrays only:

// In ColumnType.java
arrayTypeSet.add(DOUBLE);
// Other types are commented out

Recommendation: Consider documenting why only these two array types are supported or plan for extending support to other types mentioned in the PR objectives.

2. Complex Type Resolution Logic

The bind variable type resolution in PGPipelineEntry.msgParseCopyOutTypeDescriptionTypeOIDs() has complex priority logic:

// First we prioritize the types we received in the PARSE message
if (msgParseParameterTypeOIDs.size() > i) {
    oid = msgParseParameterTypeOIDs.getQuick(i);
}

// if there was no type in the PARSE message, we use the type inferred by the compiler
final Function f = bindVariableService.getFunction(i);
int nativeType;
if (f != null) {
    nativeType = f.getType();
    if (oid == PG_UNSPECIFIED || oid == X_PG_VOID) {
        oid = Numbers.bswap(PGOids.getTypeOid(nativeType));
    }
}

Recommendation: Consider adding more detailed comments explaining the precedence rules and edge cases.

3. Test Coverage

With 65.38% coverage, there are significant untested paths, particularly in:

  • PGPipelineEntry.java (6.45% coverage)
  • Error handling paths
  • Edge cases in type conversion

Positive Aspects

1. Comprehensive Type Validation

The implementation properly validates unsupported types and provides clear error messages.

2. Client Compatibility

The changes specifically address tokio-postgres and sqlx compatibility issues, which is excellent for ecosystem support.

3. Backward Compatibility

The changes appear to maintain backward compatibility while fixing the identified issues.

Minor Suggestions

1. Code Organization

Consider extracting some of the complex type resolution logic into separate methods for better readability:

private int resolveBindVariableOid(int variableIndex, Function function) {
    // Extract the OID resolution logic here
}

2. Constants

Some magic numbers could be extracted to named constants:

private static final int BIND_VARIABLE_INDEX_OFFSET = 1; // for the -1 adjustment

Conclusion

This is a solid improvement that addresses real compatibility issues with PostgreSQL drivers. The implementation is thorough and handles edge cases well. The main areas for improvement are expanding test coverage and potentially extending array type support. The changes should significantly improve the user experience when using bind variables with functions in QuestDB.

The PR successfully addresses the stated objectives around type validation, client compatibility, and function signature resolution.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🔭 Outside diff range comments (3)
core/src/main/java/io/questdb/cairo/ColumnType.java (1)

211-221: Assert-only validation risks invalid array encodings in production

Both nDims bounds and element-type support checks are guarded by assertions. In production (asserts typically off), invalid values can slip through silently. Recommend adding fast runtime guards while keeping asserts for dev.

Apply this diff to add defensive checks without changing behavior for valid inputs:

-    public static int encodeArrayType(short elemType, int nDims, boolean checkSupportedElementTypes) {
-        assert nDims >= 1 && nDims <= ARRAY_NDIMS_LIMIT : "nDims out of range: " + nDims;
-        assert !checkSupportedElementTypes || (isSupportedArrayElementType(elemType) || elemType == UNDEFINED)
-                : "not supported as array element type: " + nameOf(elemType);
+    public static int encodeArrayType(short elemType, int nDims, boolean checkSupportedElementTypes) {
+        assert nDims >= 1 && nDims <= ARRAY_NDIMS_LIMIT : "nDims out of range: " + nDims;
+        if (nDims < 1 || nDims > ARRAY_NDIMS_LIMIT) {
+            throw CairoException.critical(0).put("nDims out of range: ").put(nDims);
+        }
+        assert !checkSupportedElementTypes || (isSupportedArrayElementType(elemType) || elemType == UNDEFINED)
+                : "not supported as array element type: " + nameOf(elemType);
+        if (checkSupportedElementTypes && !(isSupportedArrayElementType(elemType) || elemType == UNDEFINED)) {
+            throw CairoException.critical(0).put("not supported as array element type: ").put(nameOf(elemType));
+        }
         nDims--; // 0 == one dimension
         return (nDims & ARRAY_NDIMS_FIELD_MASK) << ARRAY_NDIMS_FIELD_POS
                 | (elemType & ARRAY_ELEMTYPE_FIELD_MASK) << ARRAY_ELEMTYPE_FIELD_POS
                 | ARRAY;
     }
core/src/main/java/io/questdb/cutlass/pgwire/PGOids.java (2)

250-273: Add PG_UUID → PG_ARR_UUID mapping in pgToArrayOid (PGOids.java)

Short: PGOids already defines PG_UUID and PG_ARR_UUID and PGPipelineEntry handles X_PG_ARR_UUID, but pgToArrayOid (core/src/main/java/io/questdb/cutlass/pgwire/PGOids.java) does not map PG_UUID. Add the case so typarray lookups (and PgTypeCatalogueCursor usage) advertise uuid[].

Files to touch

  • core/src/main/java/io/questdb/cutlass/pgwire/PGOids.java — add PG_UUID case in pgToArrayOid (method around line ~250).
  • core/src/main/java/io/questdb/griffin/engine/functions/catalogue/PgTypeCatalogueCursor.java — uses pgToArrayOid; will then report uuid[].
  • core/src/main/java/io/questdb/cutlass/pgwire/PGPipelineEntry.java — already handles X_PG_ARR_UUID, no change needed.

Suggested diff

             case PG_VARCHAR:
                 return PG_ARR_VARCHAR;
+            case PG_UUID:
+                return PG_ARR_UUID;
             default:
                 return 0;

Note: Leave DATE unmapped in pgToArrayOid (QuestDB intentionally maps ColumnType.DATE to TIMESTAMP elsewhere).


231-240: pgArrayToElementType should mirror pgToArrayOid (add missing array→element mappings)

pgToArrayOid returns array OIDs for BOOL, INT2, INT4, INT8, FLOAT4, FLOAT8, TIMESTAMP, TIMESTAMPTZ, VARCHAR, but pgArrayToElementType currently only recognizes FLOAT8[] and INT8[]. This asymmetry can break array detection (see PgTypeCatalogueCursor, PGPipelineEntry, PGNonNullBinaryArrayView).

  • Fix: update core/src/main/java/io/questdb/cutlass/pgwire/PGOids.java -> pgArrayToElementType to include the missing cases:
     public static int pgArrayToElementType(int pgOid) {
         switch (pgOid) {
+            case PG_ARR_BOOL:
+                return PG_BOOL;
+            case PG_ARR_INT2:
+                return PG_INT2;
+            case PG_ARR_INT4:
+                return PG_INT4;
             case PG_ARR_FLOAT8:
                 return PG_FLOAT8;
+            case PG_ARR_FLOAT4:
+                return PG_FLOAT4;
             case PG_ARR_INT8:
                 return PG_INT8;
+            case PG_ARR_TIMESTAMP:
+                return PG_TIMESTAMP;
+            case PG_ARR_TIMESTAMP_TZ:
+                return PG_TIMESTAMP_TZ;
+            case PG_ARR_VARCHAR:
+                return PG_VARCHAR;
             default:
                 return 0;
         }
     }

If the restriction to FLOAT8[] and INT8[] is intentional (only those arrays are expected in binary), please add a clarifying comment in the method instead of widening the mapping.

🧹 Nitpick comments (4)
core/src/main/java/io/questdb/cutlass/pgwire/PGPipelineEntry.java (1)

1312-1347: Comprehensive array bind-type definitions: good coverage, consider small cleanup

  • Additions for BOOL, UUID, BYTEA, (VAR)CHAR, INT2/4/8, FLOAT4/8, DATE arrays are clear and consistent.
  • Minor nit: these cases duplicate encodeArrayType(elem, 1, false). Consider a small helper to reduce repetition if you touch this again.
core/src/main/java/io/questdb/cairo/ColumnType.java (1)

516-527: Registering all N-D array names irrespective of support can mislead users

This method registers array type names for all dimensions and for any base type passed in, while calling encodeArrayType(..., false) to bypass support checks. Given arrayTypeSet currently contains only a subset (e.g., DOUBLE), users can successfully reference names like "uuid[][]" that later fail at binding/casting.

  • Either gate registration by support (for storage and/or PG semantics), or
  • Keep the names but ensure any unsupported use fails with a precise, early error (ideally at parse time), and document the intent.

If you want to avoid surfacing unsupported multi-dimensional arrays for now, minimally constrain registration to 1-D for non-supported element types:

-        for (int d = 1; d <= ARRAY_NDIMS_LIMIT; d++) {
+        final boolean supported = isSupportedArrayElementType(type);
+        final int maxDims = supported ? ARRAY_NDIMS_LIMIT : 1;
+        for (int d = 1; d <= maxDims; d++) {
             sink.put("[]");
             int arrayType = encodeArrayType(type, d, false);
             String name = sink.toString();
             typeNameMap.put(arrayType, name);
             nameTypeMap.put(name, arrayType);
         }

Please confirm the intended scope: should multi-dimensional arrays be surfaced for all element types at the type-name level today, or only for element types that are actually supported in bindings/columns?

core/src/main/java/io/questdb/cutlass/pgwire/PGOids.java (2)

107-141: Reduce boilerplate for swapped OID constants

These X_PG_* and X_PG_ARR_* constants are a straightforward byte swap. Consider extracting a private static helper to compute swapped OIDs to avoid duplication and maintenance burden.

Example:

private static int x(int oid) {
    return ((oid >> 24) & 0xff) | ((oid << 8) & 0xff0000) | ((oid >> 8) & 0xff00) | ((oid << 24) & 0xff000000);
}

Then: public static final int X_PG_ARR_BOOL = x(PG_ARR_BOOL); etc.


321-323: TYPE_ARR_OIDS only maps DOUBLE[] and LONG[]; align with exposed capabilities

Despite the broadened OID catalog, only DOUBLE and LONG have array OID mappings here. If the intent is to support additional array element types over PG wire soon (e.g., INT4[] or VARCHAR[]), add their mappings when ready. Otherwise, document this limitation to avoid confusion.

Would you like a follow-up patch that:

  • Adds mappings for other safe/practical element types, and
  • Synchronizes ColumnType.arrayTypeSet accordingly?
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b150294 and a0a4586.

📒 Files selected for processing (7)
  • core/src/main/java/io/questdb/cairo/ColumnType.java (4 hunks)
  • core/src/main/java/io/questdb/cutlass/pgwire/PGOids.java (5 hunks)
  • core/src/main/java/io/questdb/cutlass/pgwire/PGPipelineEntry.java (2 hunks)
  • core/src/main/java/io/questdb/griffin/FunctionParser.java (5 hunks)
  • core/src/test/java/io/questdb/test/cutlass/pgwire/PGArraysTest.java (9 hunks)
  • core/src/test/java/io/questdb/test/griffin/DBeaverTest.java (1 hunks)
  • core/src/test/java/io/questdb/test/griffin/engine/functions/catalogue/PgTypeFunctionFactoryTest.java (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (27)
  • GitHub Check: New pull request (SelfHosted Other tests on linux-x64-zfs)
  • GitHub Check: New pull request (SelfHosted Griffin And Fuzz tests on linux-x64-zfs)
  • GitHub Check: New pull request (SelfHosted Other tests on linux-arm64)
  • GitHub Check: New pull request (Hosted Running tests on windows-other)
  • GitHub Check: New pull request (Hosted Running tests on windows-pgwire)
  • GitHub Check: New pull request (Hosted Running tests on windows-cairo)
  • GitHub Check: New pull request (Hosted Running tests on windows-fuzz2)
  • GitHub Check: New pull request (Hosted Running tests on windows-fuzz1)
  • GitHub Check: New pull request (Hosted Running tests on windows-griffin)
  • GitHub Check: New pull request (Hosted Running tests on mac-other)
  • GitHub Check: New pull request (Hosted Running tests on mac-pgwire)
  • GitHub Check: New pull request (Hosted Running tests on mac-cairo-fuzz)
  • GitHub Check: New pull request (Hosted Running tests on mac-cairo)
  • GitHub Check: New pull request (SelfHosted Griffin And Fuzz tests Start ARM Agent)
  • GitHub Check: New pull request (SelfHosted Griffin And Fuzz tests Start X64Zfs Agent)
  • GitHub Check: New pull request (Hosted Running tests on mac-griffin)
  • GitHub Check: New pull request (Rust Test and Lint on linux-jdk17)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-other)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-pgwire)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-cairo)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-fuzz)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-griffin)
  • GitHub Check: New pull request (SelfHosted Other tests Start X64Zfs Agent)
  • GitHub Check: New pull request (SelfHosted Other tests Start ARM Agent)
  • GitHub Check: New pull request (Check Changes Check changes)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (19)
core/src/test/java/io/questdb/test/griffin/DBeaverTest.java (1)

165-179: Aligning typarray OIDs with PostgreSQL: LGTM

Updated typarray values for bool, int2/4/8, float4, varchar, and timestamp correctly reflect standard array OIDs (1000, 1005, 1007, 1016, 1021, 1015, 1115). This matches the broader array-type support and improves client compatibility in tooling like DBeaver.

core/src/test/java/io/questdb/test/griffin/engine/functions/catalogue/PgTypeFunctionFactoryTest.java (2)

37-45: Correct typarray OIDs for basic types: LGTM

The typarray column now exposes proper array OIDs for varchar, timestamp, float4, int2/4/8, and bool, which aligns with server-side array support and helps driver-side type resolution.


64-72: Prefixed PgType expectations updated: LGTM

The prefixed pg_type query expectations mirror the same OID corrections and look consistent.

core/src/test/java/io/questdb/test/cutlass/pgwire/PGArraysTest.java (8)

101-101: Use of float8 for array binding: LGTM

Switching to float8 aligns with introduced array OIDs and the array encoding path. This increases determinism across drivers.


156-157: Clarified assertion rationale: LGTM

The comment now clearly explains why error messages differ between text vs binary-mode array transmission.


173-175: Test for 1D->2D dimension mismatch: LGTM

Creating a float8 1D array against a double[][] column is a good negative test for dimension validation.


178-184: Flexible assertion for driver/server mode variance: LGTM

Using assertContainsEither to accommodate mode-dependent error text avoids flaky tests while still validating correctness.


194-199: More dimensions than expected: LGTM

Mirrors the opposite mismatch scenario. Good coverage.


423-425: Empty array binding: LGTM

Ensures empty array insertion works as expected in the new encoding path.


496-509: Jagged array rejection (variant 1): LGTM

Robustly accounts for both text and binary protocol behaviors. This is important given pgjdbc’s jagged-array gap.


512-525: Jagged array rejection (variant 2): LGTM

Complements the previous case; maintains deterministic checks.

core/src/main/java/io/questdb/cutlass/pgwire/PGPipelineEntry.java (2)

1290-1293: Array OID → native array mapping for timestamps: LGTM

Mapping X_PG_ARR_TIMESTAMP/_TZ to TIMESTAMP[] via ColumnType.encodeArrayType is consistent with the rest of the array handling and keeps timezone normalization on the server side.


1353-1371: Clear rejections for unsupported (array) types: LGTM

Explicit non-critical exceptions for NUMERIC, TIME, INET, INTERVAL, JSONB and their arrays reduce ambiguity and improve client error messages.

core/src/main/java/io/questdb/griffin/FunctionParser.java (3)

794-840: Cast + undefined bind var defaults: sensible and pragmatic

  • Avoiding arbitrary overload selection by assigning a default type for underdefined bind variables within cast() is a good call:
    • textual targets → STRING
    • numeric targets → DOUBLE
    • array targets → assigned to the array type, optionally short-circuiting when it matches
      This will significantly reduce “wrong overload” surprises with clients that send UNDEFINED types.

892-909: Array-aware overload resolution for UNDEFINED: LGTM

Treating UNDEFINED on array parameters as a fuzzy match instead of a hard no-match broadens viable candidates, enabling later, precise type assignment. This matches the PR goal of bind-variable inference.


1054-1063: Assign array type to UNDEFINED based on candidate signature: LGTM

This ensures bind variables become e.g. DOUBLE[] instead of a plain scalar, allowing proper downstream validation and casting behavior.

core/src/main/java/io/questdb/cairo/ColumnType.java (1)

191-194: Good API: overload delegates to the stricter variant

The 2-arg overload cleanly routes through the 3-arg method, centralizing validation. No issues.

core/src/main/java/io/questdb/cutlass/pgwire/PGOids.java (2)

53-71: New array OID constants look correct

The OIDs for common array types (e.g., 1000 bool[], 1007 int4[], 1016 int8[], 1022 float8[], 1115 timestamp[], 1185 timestamptz[], 1015 varchar[]) match PostgreSQL values. Good coverage.


79-91: New scalar OIDs (INET, INTERVAL, JSONB, NUMERIC, TIME) are accurate

These constants align with PostgreSQL OID assignments. No issues. Ensure unsupported types (INET/INTERVAL and their arrays) are rejected upstream as per PR objectives.

Confirm that error paths in PGPipelineEntry or FunctionParser produce the intended messages for unsupported types referencing these OIDs.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/src/main/java/io/questdb/griffin/engine/functions/array/DoubleArrayDotProductFunctionFactory.java (1)

158-165: Critical indexing bug in recursive path (uses left index for right array).

At deepest dim, rightVal uses flatIndexLeft instead of flatIndexRight, producing wrong results for non‑vanilla arrays.

Apply this fix:

-                    double rightVal = right.getDouble(flatIndexLeft);
+                    double rightVal = right.getDouble(flatIndexRight);

Recommend adding a test that forces the non‑vanilla path (e.g., sliced/strided arrays with identical shapes) to catch this class of bugs.

♻️ Duplicate comments (3)
core/src/main/java/io/questdb/griffin/SqlCodeGenerator.java (1)

2225-2255: Replace asserts with runtime guards and enrich array-cast error messages.

Asserts can be disabled in production. If non‑DOUBLE arrays reach this path, DOUBLE‑specific cast funcs may be constructed, risking incorrect behavior. Guard at runtime and include dimensionality in errors.

Apply this diff:

-                                assert ColumnType.decodeArrayElementType(fromType) == DOUBLE;
-                                assert ColumnType.decodeArrayElementType(toType) == DOUBLE;
+                                if (ColumnType.decodeArrayElementType(fromType) != DOUBLE
+                                        || ColumnType.decodeArrayElementType(toType) != DOUBLE) {
+                                    throw SqlException.unsupportedCast(
+                                            modelPosition,
+                                            castFromMetadata.getColumnName(i),
+                                            fromType,
+                                            toType
+                                    );
+                                }
@@
-                                final int fromDims = ColumnType.decodeArrayDimensionality(fromType);
-                                final int toDims = ColumnType.decodeArrayDimensionality(toType);
-                                if (toDims == -1) {
-                                    throw SqlException.$(modelPosition, "cast to array bind variable type is not supported [column=")
-                                            .put(castFromMetadata.getColumnName(i)).put(']');
-                                }
+                                final int fromDims = ColumnType.decodeArrayDimensionality(fromType);
+                                final int toDims = ColumnType.decodeArrayDimensionality(toType);
+                                if (toDims == -1) {
+                                    throw SqlException.$(modelPosition, "cast to array bind variable type is not supported [column=")
+                                            .put(castFromMetadata.getColumnName(i))
+                                            .put(", toDims=").put(toDims).put(']');
+                                }
@@
-                                    if (fromDims > toDims) {
-                                        throw SqlException.$(modelPosition, "array cast to lower dimensionality is not supported [column=")
-                                                .put(castFromMetadata.getColumnName(i)).put(']');
-                                    }
+                                    if (fromDims > toDims) {
+                                        throw SqlException.$(modelPosition, "array cast to lower dimensionality is not supported [column=")
+                                                .put(castFromMetadata.getColumnName(i))
+                                                .put(", fromDims=").put(fromDims)
+                                                .put(", toDims=").put(toDims).put(']');
+                                    }
@@
-                                assert ColumnType.decodeArrayElementType(toType) == DOUBLE;
-                                final int dims = ColumnType.decodeArrayDimensionality(toType);
-                                if (dims == -1) {
-                                    throw SqlException.$(modelPosition, "cast to array bind variable type is not supported [column=")
-                                            .put(castFromMetadata.getColumnName(i)).put(']');
-                                }
+                                if (ColumnType.decodeArrayElementType(toType) != DOUBLE) {
+                                    throw SqlException.unsupportedCast(
+                                            modelPosition,
+                                            castFromMetadata.getColumnName(i),
+                                            fromType,
+                                            toType
+                                    );
+                                }
+                                final int dims = ColumnType.decodeArrayDimensionality(toType);
+                                if (dims == -1) {
+                                    throw SqlException.$(modelPosition, "cast to array bind variable type is not supported [column=")
+                                            .put(castFromMetadata.getColumnName(i))
+                                            .put(", toDims=").put(dims).put(']');
+                                }
core/src/main/java/io/questdb/cairo/ColumnType.java (1)

759-771: Revisit LONG[] runtime support alignment.

arrayTypeSet includes DOUBLE only; PG wire appears to map INT8[] (LONG[]) too in this PR. If LONG[] is intended to be supported end‑to‑end, add LONG here; otherwise confirm PG path rejects it consistently.

#!/bin/bash
set -euo pipefail
# Check runtime support set
rg -n 'arrayTypeSet\.add\(' core/src/main/java/io/questdb/cairo/ColumnType.java -n
# Check PG OID mapping for INT8[]
rg -nP 'ARR.*(INT8|BIGINT)|PG_ARR_INT8|INT8\[\]' -n core/src/main/java
core/src/main/java/io/questdb/cutlass/line/tcp/ArrayBinaryFormatParser.java (1)

89-92: nDims read as unsigned: LGTM.

This fixes spurious negatives from Unsafe.getByte.

Ensure a test exists for nDims=0xFF → ARRAY_TOO_MANY_DIMENSIONS:

#!/bin/bash
set -euo pipefail
rg -n 'ARRAY_TOO_MANY_DIMENSIONS|tooManyDims\(\)' core/src/test -C2
🧹 Nitpick comments (7)
core/src/main/java/io/questdb/griffin/engine/functions/finance/LevelTwoPriceArrayFunctionFactory.java (2)

101-107: Guard non‑positive targets (t <= 0).

Prevents nonsensical pricing when target is zero/negative and avoids corner path returning the first price for t == 0.

Apply:

         @Override
         public double getDouble(Record rec) {
             final double t = targetArg.getDouble(rec);
+            if (!(t > 0)) {
+                return Double.NaN;
+            }
             final ArrayView pricesArr = pricesArg.getArray(rec);
             final ArrayView sizesArr = sizesArg.getArray(rec);
             if (pricesArr.isNull() || sizesArr.isNull()) {
                 return Double.NaN;
             }

110-112: Make the length‑mismatch error more actionable.

Include actual lengths to speed up debugging.

Apply:

-                throw CairoException.nonCritical().position(sizesArgPos)
-                        .put("prices array length doesn't match sizes array length");
+                throw CairoException.nonCritical().position(sizesArgPos)
+                        .put("prices array length (").put(len)
+                        .put(") doesn't match sizes array length (")
+                        .put(sizesArr.getDimLen(0)).put(')');
core/src/main/java/io/questdb/griffin/SqlCodeGenerator.java (1)

835-847: Add column context when UNION type widening fails due to array bind vars.

getUnionCastType now throws, but the error surfaces without column info. Catch here and rethrow with the offending column name for better diagnostics.

Apply this diff:

-        for (int i = 0; i < columnCount; i++) {
-            int typeA = typesA.getColumnType(i);
-            int typeB = typesB.getColumnType(i);
-            int targetType = getUnionCastType(typeA, typeB);
-            metadata.add(new TableColumnMetadata(typesA.getColumnName(i), targetType));
-        }
+        for (int i = 0; i < columnCount; i++) {
+            final int typeA = typesA.getColumnType(i);
+            final int typeB = typesB.getColumnType(i);
+            final int targetType;
+            try {
+                targetType = getUnionCastType(typeA, typeB);
+            } catch (SqlException e) {
+                // Provide column context; position is unknown at this layer.
+                throw SqlException.$(0, "array bind variables are not supported in UNION queries [column=")
+                        .put(typesA.getColumnName(i)).put(']');
+            }
+            metadata.add(new TableColumnMetadata(typesA.getColumnName(i), targetType));
+        }
core/src/main/java/io/questdb/cairo/ColumnType.java (3)

223-233: Avoid assert‑only validation for prod paths.

Asserts may be disabled; enforce checkSupportedElementTypes at runtime.

-        assert !checkSupportedElementTypes || (isSupportedArrayElementType(elemType) || elemType == UNDEFINED)
-                : "not supported as array element type: " + nameOf(elemType);
+        if (checkSupportedElementTypes && !isSupportedArrayElementType(elemType) && elemType != UNDEFINED) {
+            throw CairoException.critical(0)
+                    .put("not supported as array element type: ").put(nameOf(elemType));
+        }

545-556: Precomputed array names: consider masking weak‑dims in nameOf for better diagnostics.

nameOf(ARRAY with weak‑dims) currently returns "unknown". Mask the flag so logs/errors show familiar names.

 public static String nameOf(int columnType) {
+        if (isArrayWithWeakDims(columnType)) {
+            columnType &= ~TYPE_FLAG_ARRAY_WEAK_DIMS;
+        }
         final int index = typeNameMap.keyIndex(columnType);
         if (index > -1) {
             return "unknown";
         }
         return typeNameMap.valueAtQuick(index);
 }

892-906: Array type names for many element types: add a clarifying comment.

Given only a subset is supported at runtime, add a one‑liner here stating these names are for error reporting/catalog friendliness.

-        addArrayTypeName(sink, ColumnType.BOOLEAN);
+        // Note: names registered below are for error messages/catalog; runtime support is limited by arrayTypeSet.
+        addArrayTypeName(sink, ColumnType.BOOLEAN);
core/src/main/java/io/questdb/cutlass/line/tcp/ArrayBinaryFormatParser.java (1)

76-86: Read elemType as unsigned for future‑proofing.

Current tags fit in < 64, but mask defensively to avoid sign extension if new tags exceed 127.

-                elemType = Unsafe.getUnsafe().getByte(addr);
+                elemType = (short) (Unsafe.getUnsafe().getByte(addr) & 0xFF);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ee2fe7d and 7f43486.

📒 Files selected for processing (9)
  • core/src/main/java/io/questdb/cairo/ColumnType.java (9 hunks)
  • core/src/main/java/io/questdb/cutlass/line/tcp/ArrayBinaryFormatParser.java (1 hunks)
  • core/src/main/java/io/questdb/griffin/SqlCodeGenerator.java (6 hunks)
  • core/src/main/java/io/questdb/griffin/engine/functions/array/DoubleArrayDotProductFunctionFactory.java (3 hunks)
  • core/src/main/java/io/questdb/griffin/engine/functions/array/DoubleMatrixMultiplyFunctionFactory.java (3 hunks)
  • core/src/main/java/io/questdb/griffin/engine/functions/finance/LevelTwoPriceArrayFunctionFactory.java (4 hunks)
  • core/src/test/java/io/questdb/test/cairo/ArrayTest.java (6 hunks)
  • core/src/test/java/io/questdb/test/cutlass/pgwire/PGJobContextTest.java (3 hunks)
  • core/src/test/java/io/questdb/test/griffin/SqlCodeGeneratorTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • core/src/main/java/io/questdb/griffin/engine/functions/array/DoubleMatrixMultiplyFunctionFactory.java
  • core/src/test/java/io/questdb/test/griffin/SqlCodeGeneratorTest.java
  • core/src/test/java/io/questdb/test/cairo/ArrayTest.java
  • core/src/test/java/io/questdb/test/cutlass/pgwire/PGJobContextTest.java
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-31T08:21:17.390Z
Learnt from: mtopolnik
PR: questdb/questdb#5997
File: core/src/main/java/io/questdb/griffin/engine/functions/array/DoubleArrayAccessFunctionFactory.java:127-131
Timestamp: 2025-07-31T08:21:17.390Z
Learning: In DoubleArrayAccessFunctionFactory.java, overflow validation for array index casting from long to int is performed in the validateIndexArgs() method rather than at each individual cast site. The validateIndexArgs() method is called early in newInstance() to validate all index arguments, making subsequent casts safe.

Applied to files:

  • core/src/main/java/io/questdb/griffin/SqlCodeGenerator.java
📚 Learning: 2025-08-04T09:16:27.366Z
Learnt from: jerrinot
PR: questdb/questdb#5996
File: core/src/test/java/io/questdb/test/cutlass/http/line/LineHttpSenderTest.java:350-356
Timestamp: 2025-08-04T09:16:27.366Z
Learning: In QuestDB ILP tests, maximum dimension values like `(1 << 28) - 1` are intentionally hard-coded instead of using constants like `ArrayView.DIM_MAX_LEN` to serve as "canaries" that will cause test failures if the API limits change, ensuring developers are aware of breaking changes to the ILP API.

Applied to files:

  • core/src/main/java/io/questdb/cutlass/line/tcp/ArrayBinaryFormatParser.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
  • GitHub Check: New pull request (SelfHosted Other tests on linux-arm64)
  • GitHub Check: New pull request (SelfHosted Griffin And Fuzz tests on linux-x64-zfs)
  • GitHub Check: New pull request (SelfHosted Other tests on linux-x64-zfs)
  • GitHub Check: New pull request (SelfHosted Griffin And Fuzz tests on linux-arm64)
  • GitHub Check: New pull request (Hosted Running tests on windows-other)
  • GitHub Check: New pull request (Hosted Running tests on windows-pgwire)
  • GitHub Check: New pull request (Hosted Running tests on windows-cairo)
  • GitHub Check: New pull request (Hosted Running tests on windows-fuzz2)
  • GitHub Check: New pull request (Hosted Running tests on windows-fuzz1)
  • GitHub Check: New pull request (Hosted Running tests on windows-griffin)
  • GitHub Check: New pull request (Hosted Running tests on mac-other)
  • GitHub Check: New pull request (Hosted Running tests on mac-pgwire)
  • GitHub Check: New pull request (Hosted Running tests on mac-cairo-fuzz)
  • GitHub Check: New pull request (Hosted Running tests on mac-cairo)
  • GitHub Check: New pull request (Rust Test and Lint on linux-jdk17)
  • GitHub Check: New pull request (SelfHosted Griffin And Fuzz tests Start ARM Agent)
  • GitHub Check: New pull request (SelfHosted Griffin And Fuzz tests Start X64Zfs Agent)
  • GitHub Check: New pull request (SelfHosted Other tests Start ARM Agent)
  • GitHub Check: New pull request (SelfHosted Other tests Start X64Zfs Agent)
  • GitHub Check: New pull request (Hosted Running tests on mac-griffin)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-other)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-pgwire)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-cairo)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-fuzz)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-griffin)
  • GitHub Check: New pull request (Check Changes Check changes)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (16)
core/src/main/java/io/questdb/griffin/engine/functions/array/DoubleArrayDotProductFunctionFactory.java (3)

33-33: Import addition is correct.

Needed for the new init override. LGTM.


76-82: Pre-init dimensionality guard looks good.

Allows weak-dim bind vars at construction time; strict check deferred to init. LGTM.


130-142: Init-time dimensionality check is appropriate.

Good call to BinaryFunction.super.init(); enforcing dims equality here matches bind-var resolution flow.

Please confirm that removing isThreadSafe() doesn’t change concurrency semantics for this function. If the default isn’t true, reintroduce the override.

core/src/main/java/io/questdb/griffin/engine/functions/finance/LevelTwoPriceArrayFunctionFactory.java (6)

33-33: Import looks correct.

Required for the new init(SymbolTableSource, SqlExecutionContext) override.


71-73: Argument/position wiring for pricesArg is correct.


82-83: Tracking pricesArgPos enables precise error reporting.


87-93: Constructor refactor LGTM.

Fields are initialized in a clear order; no behavioral change.


167-167: toPlan ordering matches the new argument order (target, sizes, prices).


154-163: ```shell
#!/bin/bash
set -euo pipefail

echo "1) Search for decodeArrayDimensionality usages..."
rg -n --hidden --no-ignore-vcs "decodeArrayDimensionality" -S || true

echo
echo "2) Locate ColumnType.* files"
rg -n --hidden --no-ignore-vcs --files "ColumnType.java" || true
rg -n --hidden --no-ignore-vcs "class ColumnType" -S || true

echo
echo "3) Show definition(s) containing decodeArrayDimensionality"
files=$(rg --hidden --no-ignore-vcs --files-with-matches "decodeArrayDimensionality" || true)
if [ -n "$files" ]; then
for f in $files; do
echo "---- $f ----"
rg -n --hidden --no-ignore-vcs "decodeArrayDimensionality" -n -C5 "$f" || true
sed -n '1,240p' "$f" | sed -n '1,240p'
echo
done
else
echo "No files contain decodeArrayDimensionality"
fi

echo
echo "4) Search for existing helpers that handle weak/strong array dimensionality (isOneDimensional*, isArray*, abs patterns)..."
rg -n --hidden --no-ignore-vcs "isOneDimensional|isOneDimensionalArray|isArray1|isArray\(|arrayDimensionality|Math\.abs\([^)]+decodeArrayDimensionality" -S || true

echo
echo "5) Show other places where decodeArrayDimensionality is compared to 1 (to check current practice)"
rg -n --hidden --no-ignore-vcs "decodeArrayDimensionality\([^)]\)\s(==|!=|>|<|>=|<=)\s*-?1" -S || true

echo
echo "Done."


</blockquote></details>
<details>
<summary>core/src/main/java/io/questdb/griffin/SqlCodeGenerator.java (2)</summary><blockquote>

`310-310`: **LGTM on import.**

No concerns with the added static import.

---

`475-497`: **Fix typo in comment; keep dimensionality guard and surface column context**

- Keep the hard error for unknown (-1) dimensionality.
- Surface the column name at the call site (see widenSetMetadata) so the error has context.
- Typo fix (apply below).

```diff
-                // if B is scalar then we coarse it to array of the same dimensionality as A is
+                // if B is scalar then we coerce it to an array with the same dimensionality as A

Verify callers handle/declare SqlException at:

  • core/src/main/java/io/questdb/griffin/SqlCodeGenerator.java:843
  • core/src/test/java/io/questdb/test/griffin/SqlCodeGeneratorTest.java:8136-8137
core/src/main/java/io/questdb/cairo/ColumnType.java (5)

234-245: encodeArrayTypeWithWeakDims: LGTM.


286-293: isArrayWithWeakDims helper: LGTM.


557-563: Array cast tightened to equal dims and non‑weak dims: LGTM.


635-639: Undefined arrays include weak‑dims: LGTM.


169-182: Weak‑dims: returning -1 is fine; verify all callers handle it.

decodeArrayDimensionality(...) returns -1 for weak dims; sandbox search here was inconclusive (ripgrep skipped files). Run locally and inspect any call sites or direct numeric comparisons:

rg -n --hidden --no-ignore -S 'decodeArrayDimensionality' -C3
rg -nP 'decodeArrayDimensionality([^)])\s(?:[><=!]=?)\s*-?\d+' -C3
git grep -n 'decodeArrayDimensionality'

If any caller compares against a constant or assumes ≥1, update it to treat -1 as "unknown" or add an explicit guard.

@puzpuzpuz puzpuzpuz self-requested a review September 26, 2025 14:39
@puzpuzpuz puzpuzpuz self-requested a review September 30, 2025 14:12
@bluestreak01 bluestreak01 added Bug Incorrect or unexpected behavior PG-Modern labels Sep 30, 2025
@glasstiger
Copy link
Copy Markdown
Contributor

[PR Coverage check]

😍 pass : 479 / 572 (83.74%)

file detail

path covered line new line coverage
🔵 io/questdb/cutlass/pgwire/PGPipelineEntry.java 2 31 06.45%
🔵 io/questdb/griffin/engine/functions/cast/CastDoubleArrayToDoubleArrayFunctionFactory.java 8 36 22.22%
🔵 io/questdb/griffin/engine/functions/bind/ArrayBindVariable.java 5 14 35.71%
🔵 io/questdb/griffin/SqlCodeGenerator.java 13 22 59.09%
🔵 io/questdb/griffin/engine/functions/cast/CastStrToDoubleArrayFunctionFactory.java 4 6 66.67%
🔵 io/questdb/griffin/FunctionParser.java 17 23 73.91%
🔵 io/questdb/griffin/engine/functions/constants/Constants.java 7 9 77.78%
🔵 io/questdb/griffin/engine/functions/cast/CastDoubleToDoubleArray.java 5 6 83.33%
🔵 io/questdb/cutlass/line/tcp/LineTcpEventBuffer.java 6 7 85.71%
🔵 io/questdb/griffin/engine/functions/finance/LevelTwoPriceArrayFunctionFactory.java 12 14 85.71%
🔵 io/questdb/cutlass/pgwire/PGOids.java 7 8 87.50%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayPositionFunctionFactory.java 26 28 92.86%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayRoundFunctionFactory.java 21 22 95.45%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayAddScalarFunctionFactory.java 7 7 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayInsertionPointAfterEqualFunctionFactory.java 10 10 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayFlattenFunctionFactory.java 1 1 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayShiftFunctionFactory.java 7 7 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleMatrixMultiplyFunctionFactory.java 18 18 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayMinFunctionFactory.java 1 1 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayAddFunctionFactory.java 17 17 100.00%
🔵 io/questdb/cairo/sql/WeakDimsArrayFunction.java 9 9 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayAccessFunctionFactory.java 4 4 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayDivFunctionFactory.java 17 17 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayShiftDefaultNaNFunctionFactory.java 7 7 100.00%
🔵 io/questdb/griffin/engine/functions/array/ArrayDimLengthFunctionFactory.java 29 29 100.00%
🔵 io/questdb/griffin/engine/functions/array/ArrayCreateFunctionFactory.java 21 21 100.00%
🔵 io/questdb/griffin/SqlParser.java 1 1 100.00%
🔵 io/questdb/cairo/ColumnType.java 42 42 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleScalarSubtractArrayFunctionFactory.java 7 7 100.00%
🔵 io/questdb/cairo/arr/FunctionArray.java 1 1 100.00%
🔵 io/questdb/cutlass/line/tcp/ArrayBinaryFormatParser.java 1 1 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayDivScalarFunctionFactory.java 7 7 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleNegArrayFunctionFactory.java 7 7 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayTransposeFunctionFactory.java 7 7 100.00%
🔵 io/questdb/griffin/engine/functions/constants/NullArrayConstant.java 1 1 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayDotProductFunctionFactory.java 12 12 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayMaxFunctionFactory.java 1 1 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleScalarDivArrayFunctionFactory.java 7 7 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayInsertionPointFunctionFactory.java 10 10 100.00%
🔵 io/questdb/griffin/UpdateOperatorImpl.java 2 2 100.00%
🔵 io/questdb/cairo/arr/MutableArray.java 4 4 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArraySubtractScalarFunctionFactory.java 7 7 100.00%
🔵 io/questdb/griffin/SqlException.java 4 4 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArraySubtractFunctionFactory.java 17 17 100.00%
🔵 io/questdb/griffin/SqlCompilerImpl.java 2 2 100.00%
🔵 io/questdb/griffin/engine/functions/eq/EqDoubleArrayFunctionFactory.java 9 9 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayMultiplyScalarFunctionFactory.java 7 7 100.00%
🔵 io/questdb/cairo/arr/ArrayView.java 1 1 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayMultiplyFunctionFactory.java 17 17 100.00%
🔵 io/questdb/cairo/arr/BorrowedArray.java 4 4 100.00%
🔵 io/questdb/griffin/engine/functions/rnd/RndDoubleArrayFunctionFactory.java 14 14 100.00%
🔵 io/questdb/cutlass/http/processors/JsonQueryProcessorState.java 1 1 100.00%
🔵 io/questdb/griffin/SqlUtil.java 2 2 100.00%
🔵 io/questdb/griffin/engine/functions/array/DoubleArrayCumSumFunctionFactory.java 3 3 100.00%

@bluestreak01 bluestreak01 merged commit 7062a29 into master Sep 30, 2025
35 checks passed
@bluestreak01 bluestreak01 deleted the vi_pg_arr_fix branch September 30, 2025 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Incorrect or unexpected behavior PG-Modern

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants