|
| 1 | +// SPDX-License-Identifier: BUSL-1.1 |
| 2 | + |
| 3 | +//! Upstream issue #223 regression: `document_strict` and `kv` engines must |
| 4 | +//! accept `INT4`/`SMALLINT` (and the other PostgreSQL integer-width |
| 5 | +//! keywords) as valid column types. Both engines validate declared column |
| 6 | +//! types via `nodedb_types::columnar::ColumnType::from_str` |
| 7 | +//! (`nodedb-sql/src/ddl_ast/collection_type.rs`'s `build_strict_schema` / |
| 8 | +//! `build_kv_collection_type`), which previously only recognized |
| 9 | +//! `BIGINT`/`INT64`/`INTEGER`/`INT` — `INT4`, `INT8`, `SMALLINT`, and `INT2` |
| 10 | +//! were rejected with "unknown column type", even though they're valid |
| 11 | +//! PostgreSQL integer aliases. |
| 12 | +//! |
| 13 | +//! This is a DDL-acceptance smoke test only: for these engines the wire OID |
| 14 | +//! stays `INT8` (20) regardless of declared width — `raw_type` refinement |
| 15 | +//! (issue #217) is schemaless/columnar-only by design, since strict/kv |
| 16 | +//! columns are typed authoritatively by the resolved `ColumnType`, not a |
| 17 | +//! separately-tracked raw string. See `pgwire_ddl_result_types.rs`'s |
| 18 | +//! `create_collection_int_widths_preserve_wire_oids` for the schemaless OID |
| 19 | +//! fidelity coverage. |
| 20 | +
|
| 21 | +mod common; |
| 22 | + |
| 23 | +use common::pgwire_harness::TestServer; |
| 24 | + |
| 25 | +/// `document_strict` `CREATE COLLECTION` with `INT4`/`SMALLINT` columns must |
| 26 | +/// succeed (previously errored with "unknown column type: 'INT4'"). |
| 27 | +#[tokio::test(flavor = "multi_thread", worker_threads = 4)] |
| 28 | +async fn strict_create_collection_accepts_int_width_aliases() { |
| 29 | + let server = TestServer::start().await; |
| 30 | + |
| 31 | + server |
| 32 | + .exec( |
| 33 | + "CREATE COLLECTION strict_int_widths (\ |
| 34 | + id TEXT PRIMARY KEY, \ |
| 35 | + a INT4, \ |
| 36 | + b SMALLINT, \ |
| 37 | + c INT2, \ |
| 38 | + d INT8\ |
| 39 | + ) WITH (engine='document_strict')", |
| 40 | + ) |
| 41 | + .await |
| 42 | + .expect("CREATE COLLECTION with INT4/SMALLINT/INT2/INT8 columns must succeed on document_strict"); |
| 43 | + |
| 44 | + server |
| 45 | + .exec("INSERT INTO strict_int_widths (id, a, b, c, d) VALUES ('r1', 1, 2, 3, 4)") |
| 46 | + .await |
| 47 | + .expect("INSERT into strict_int_widths must succeed"); |
| 48 | + |
| 49 | + let stmt = server |
| 50 | + .client |
| 51 | + .prepare_typed( |
| 52 | + "SELECT id, a, b, c, d FROM strict_int_widths WHERE id = $1", |
| 53 | + &[tokio_postgres::types::Type::TEXT], |
| 54 | + ) |
| 55 | + .await |
| 56 | + .expect("prepare strict_int_widths select"); |
| 57 | + let rows = server |
| 58 | + .client |
| 59 | + .query(&stmt, &[&"r1"]) |
| 60 | + .await |
| 61 | + .expect("execute strict_int_widths select"); |
| 62 | + assert_eq!(rows.len(), 1, "expected 1 row back from strict_int_widths"); |
| 63 | + |
| 64 | + // Load-bearing: document_strict stays INT8 (20) regardless of declared |
| 65 | + // width — strict columns carry no `raw_type` (they're already typed |
| 66 | + // authoritatively by `ColumnType`), so the issue #217 refinement never |
| 67 | + // applies here. Width narrowing is schemaless/columnar-only by design. |
| 68 | + for col_name in ["a", "b", "c", "d"] { |
| 69 | + if let Some(col) = rows[0].columns().iter().find(|c| c.name() == col_name) { |
| 70 | + assert_eq!( |
| 71 | + col.type_().oid(), |
| 72 | + 20, |
| 73 | + "strict column '{col_name}' OID must stay INT8 (20), got {}", |
| 74 | + col.type_().oid() |
| 75 | + ); |
| 76 | + } |
| 77 | + } |
| 78 | +} |
| 79 | + |
| 80 | +/// `kv` `CREATE COLLECTION` with `INT4`/`SMALLINT` columns must succeed |
| 81 | +/// (previously errored with "unknown column type: 'INT4'"). The kv OID |
| 82 | +/// stays INT8 (20) — do not assert a narrowed OID here. |
| 83 | +#[tokio::test(flavor = "multi_thread", worker_threads = 4)] |
| 84 | +async fn kv_create_collection_accepts_int_width_aliases() { |
| 85 | + let server = TestServer::start().await; |
| 86 | + |
| 87 | + server |
| 88 | + .exec( |
| 89 | + "CREATE COLLECTION kv_int_widths (\ |
| 90 | + key TEXT PRIMARY KEY, \ |
| 91 | + a INT4, \ |
| 92 | + b SMALLINT\ |
| 93 | + ) WITH (engine='kv')", |
| 94 | + ) |
| 95 | + .await |
| 96 | + .expect("CREATE COLLECTION with INT4/SMALLINT columns must succeed on kv"); |
| 97 | + |
| 98 | + server |
| 99 | + .exec("INSERT INTO kv_int_widths (key, a, b) VALUES ('r1', 1, 2)") |
| 100 | + .await |
| 101 | + .expect("INSERT into kv_int_widths must succeed"); |
| 102 | + |
| 103 | + let stmt = server |
| 104 | + .client |
| 105 | + .prepare_typed( |
| 106 | + "SELECT key, a, b FROM kv_int_widths WHERE key = $1", |
| 107 | + &[tokio_postgres::types::Type::TEXT], |
| 108 | + ) |
| 109 | + .await |
| 110 | + .expect("prepare kv_int_widths select"); |
| 111 | + let rows = server |
| 112 | + .client |
| 113 | + .query(&stmt, &[&"r1"]) |
| 114 | + .await |
| 115 | + .expect("execute kv_int_widths select"); |
| 116 | + assert_eq!(rows.len(), 1, "expected 1 row back from kv_int_widths"); |
| 117 | + |
| 118 | + // Load-bearing: kv stays INT8 (20) — the fix does not widen/narrow kv's |
| 119 | + // wire type, only schemaless/columnar's. |
| 120 | + for col_name in ["a", "b"] { |
| 121 | + if let Some(col) = rows[0].columns().iter().find(|c| c.name() == col_name) { |
| 122 | + assert_eq!( |
| 123 | + col.type_().oid(), |
| 124 | + 20, |
| 125 | + "kv column '{col_name}' OID must stay INT8 (20), got {}", |
| 126 | + col.type_().oid() |
| 127 | + ); |
| 128 | + } |
| 129 | + } |
| 130 | +} |
0 commit comments