Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 10 additions & 13 deletions test/arrow_import.sh
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 +114,6 @@ fifo_release() { exec 9<>"$1" 2>/dev/null; exec 9>&- 2>/dev/null; }
have_pyarrow=1
python3 -c 'import pyarrow' 2>/dev/null || have_pyarrow=0

expect_error() {
local label="$1" sql="$2"
if psql_run "$sql" >/dev/null 2>&1; then
check "$label (expected error)" "succeeded" "error"
else
check "$label" "error" "error"
fi
}

ARROW="$PGC_WORKDIR/rt.arrows"

# --- 1. round trip through pgColumnar's own writer ---------------------------
Expand Down Expand Up @@ -332,10 +323,16 @@ fi

# --- 4. error cases ---------------------------------------------------------
echo "-- argument validation"
# BY SQLSTATE (#1341). These accepted any error at all, and a check that failed
# was recorded under a different name, "<label> (expected error)", so its red
# never reached the name the ledger keeps. 42809 is wrong_object_type, 42804
# datatype_mismatch; an empty state is a success.
psql_run "CREATE TABLE ri_heap (a bigint, b float8, c text) USING heap;"
expect_error "reject non-columnar target" "SELECT pgcolumnar.import_arrow('ri_heap', '$ARROW');"
check "reject non-columnar target" \
"$(sqlstate_or_hang "SELECT pgcolumnar.import_arrow('ri_heap', '$ARROW')")" "42809"
psql_run "CREATE TABLE ri_wrong (a int) USING pgcolumnar;"
expect_error "reject column-count mismatch" "SELECT pgcolumnar.import_arrow('ri_wrong', '$ARROW');"
check "reject column-count mismatch" \
"$(sqlstate_or_hang "SELECT pgcolumnar.import_arrow('ri_wrong', '$ARROW')")" "42804"

if [ "$have_pyarrow" = 1 ]; then
DICTF="$PGC_WORKDIR/dict.arrows"
Expand Down Expand Up @@ -790,8 +787,8 @@ check "import into an indexed table: a point lookup finds its row" \
psql_run "CREATE TABLE ix_uq (id int, v text) USING pgcolumnar;"
psql_run "CREATE UNIQUE INDEX ix_uq_id ON ix_uq (id);"
psql_run "SELECT pgcolumnar.import_arrow('ix_uq', '$IXFILE');"
expect_error "importing the same keys twice raises unique_violation" \
"SELECT pgcolumnar.import_arrow('ix_uq', '$IXFILE');"
check "importing the same keys twice raises unique_violation" \
"$(sqlstate_or_hang "SELECT pgcolumnar.import_arrow('ix_uq', '$IXFILE')")" "23505"
check "the failed second import left the row count alone" \
"$(q 'SELECT count(*) FROM ix_uq;')" "3000"

Expand Down
4 changes: 2 additions & 2 deletions test/check_ledger.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ arrow_import arrow_import premise: this pyarrow writes a compressed body (zstd o
arrow_import arrow_import pyarrow import rows 15;16;17;18;19 never -
arrow_import arrow_import pyarrow values 15;16;17;18;19 never -
arrow_import arrow_import reject a compressed record-batch body 15;16;17;18;19 2026-10-14 import_arrow without its compressed-body refusal
arrow_import arrow_import reject column-count mismatch 15;16;17;18;19 never -
arrow_import arrow_import reject column-count mismatch 15;16;17;18;19 2026-10-14 import_arrow without its column-count check
arrow_import arrow_import reject dictionary-encoded file 15;16;17;18;19 2026-10-14 import_arrow without its dictionary-batch refusal
arrow_import arrow_import reject non-columnar target 15;16;17;18;19 never -
arrow_import arrow_import reject non-columnar target 15;16;17;18;19 2026-10-14 import_arrow without its columnar-relation check
arrow_import arrow_import round trip identical 15;16;17;18;19 never -
arrow_import arrow_import so does a microsecond-exact nanosecond file 15;16;17;18;19 never -
arrow_import arrow_import the failed second import left the row count alone 15;16;17;18;19 never -
Expand Down
16 changes: 15 additions & 1 deletion test/check_ledger_budget.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2002,4 +2002,18 @@ suites_not_covered 242
# never 1925 + 8 - 3 = 1930
# dated 580 + 3 = 583
# 1930 + 583 == 2513
checks_never_observed_red 1930
#
# #1341, arrow_import's pytest twin, and its argument arms by SQLSTATE (OffgridwithJD):
# 1930 -> 1928. No new rows. "reject non-columnar target" and "reject column-count
# mismatch" accepted any error, and a failure was recorded as "<name> (expected
# error)", so a red never reached the row. They now assert 42809 and 42804, and each is
# dated by its check removed: without the relation check the import fails 42804
# instead, which main's suite accepts; without the count check a 16-column file
# imports into a 1-column table, which main's suite reports under the other name.
# Five-major runs: 77/77 on 15-19, the twin 6 passed with pyarrow required.
#
# ledger rows 2513 = 2513
# never 1930 - 2 = 1928
# dated 583 + 2 = 585
# 1928 + 585 == 2513
checks_never_observed_red 1928
16 changes: 16 additions & 0 deletions test/pytest/TESTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ behaviour, the source of that number is named.
- [105. test_import_export_privilege.py: import and export check the table's privilege, serial and parallel](#105-test_import_export_privilegepy-import-and-export-check-the-tables-privilege-serial-and-parallel)
- [106. test_every_suite_job_installs_the_extensions.py: every job that runs the suites installs the extension packages](#106-test_every_suite_job_installs_the_extensionspy-every-job-that-runs-the-suites-installs-the-extension-packages)
- [107. test_fdw_plan_privilege.py: planning a foreign table reads no server file for a role the scan would refuse](#107-test_fdw_plan_privilegepy-planning-a-foreign-table-reads-no-server-file-for-a-role-the-scan-would-refuse)
- [108. test_arrow_import.py: import_arrow round trips, reads a foreign file, and refuses what it cannot decode](#108-test_arrow_importpy-import_arrow-round-trips-reads-a-foreign-file-and-refuses-what-it-cannot-decode)

## 1. How to read a test in here

Expand Down Expand Up @@ -6859,3 +6860,18 @@ The pytest twin of `test/fdw_plan_privilege.sh`. A planner estimate is visible t
| test | what it holds |
| --- | --- |
| `test_fdw_planning_reads_no_server_file_for_an_unprivileged_role` | a role without `pg_read_server_files` gets the flat estimate from both wrappers and plans a missing Iceberg path the same as a real one, while the scan still refuses it (42501); a privileged role gets the manifest count and the size estimate (controls) |

## 108. test_arrow_import.py: import_arrow round trips, reads a foreign file, and refuses what it cannot decode

The pytest twin of `test/arrow_import.sh` (ported for #1341), every check by the shell's name. A 16-column table survives export and import exactly (a set hash on both sides), non-finite dates and NaN numerics arrive as null, and a non-columnar target and a column-count mismatch are refused by SQLSTATE. A pyarrow-written file imports with its values; nanosecond values are floored to the microsecond and the loss is reported once, counted in VALUES (two columns, so values and rows differ), never refused; a dictionary batch and a compressed body are refused by SQLSTATE and message; every Arrow date, time and timestamp carrier and unit decodes to the instant it holds or is refused 22008, a file whose declared type does not match its column is refused 42804, and nested units are honoured. An import maintains plain, unique (23505 on a second import) and partial indexes, and a FIFO is refused rather than hung. The four pyarrow tests decline by name without pyarrow, and fail where `PGC_REQUIRE` names it.

### Every test

| test | what it holds |
| --- | --- |
| `test_a_round_trip_and_the_documented_lossy_mapping` | export and import counts, the identical round trip, the non-finite mapping, and the two argument refusals |
| `test_a_file_pyarrow_wrote` | a foreign file's row count and values |
| `test_nanosecond_narrowing_is_reported_never_refused` | every row kept, the loss counted in values (8, then 12 through time64 and a list), no report on the two controls, and the floor |
| `test_the_refusals_and_every_temporal_carrier` | the dictionary and compressed refusals, every carrier and unit, the 22008 guards, the 42804 type matches with their controls, an empty target after a refusal, and nested units |
| `test_an_import_maintains_the_tables_indexes` | the plan really uses the index, index and sequential scans agree, the unique violation and its row count, and the partial index |
| `test_a_fifo_is_refused_not_a_hang` | XX001 within the wall clock, and the backend still up |
4 changes: 3 additions & 1 deletion test/pytest/expected_tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -647,4 +647,6 @@ guard_tests 433
#
# cluster_tests 542 -> 543 for test_fdw_plan_privilege.py, one test, the twin of
# test/fdw_plan_privilege.sh, by collection over the cluster files on this branch.
cluster_tests 543
# cluster_tests 543 -> 549 for #1341's test_arrow_import.py, the twin of arrow_import.sh:
# six tests, by collection over the cluster files on this tree.
cluster_tests 549
Loading
Loading