From f846ca10aaec001bb9b3140b2ed942d0e1b573a3 Mon Sep 17 00:00:00 2001 From: SandeepDave2 Date: Tue, 14 Jul 2026 16:31:05 -0600 Subject: [PATCH 1/4] Fix plain COPY crash and restore copy_test to test suite --- Makefile | 15 +++++++++++++++ ODBCLoader.cpp | 16 ++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5b42d55..511c42e 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,21 @@ test: @echo "Running ODBCLoader Test Suite" @echo "=========================================" @echo "" + @echo "[*] Running Copy Test..." + @echo "" + @$(VSQL) -f tests/copy_test.sql 2>&1 | tee $(TMPDIR)/copy_test.out | perl -pe 's/^vsql:[\/_:\w\.]* /vsql: /; \ + s/\[ODBC[^\]]*\]/[...]/g; \ + s/\[mysql[^\]]*\]/[...]/g; \ + s/(Error parsing .* )\(.*\)$$/$$1(...)/; \ + s/mariadb/MySQL/ig; ' + @echo "" + @echo "[*] Validating copy test output..." + @diff -u tests/expected/copy_test.out <(perl -pe 's/^vsql:[\/_:\w\.]* /vsql: /; \ + s/\[ODBC[^\]]*\]/[...]/g; \ + s/\[mysql[^\]]*\]/[...]/g; \ + s/(Error parsing .* )\(.*\)$$/$$1(...)/; \ + s/mariadb/MySQL/ig; ' $(TMPDIR)/copy_test.out) && echo "[✓] Copy test validation passed" || (echo "[✗] Copy test validation failed" && exit 1) + @echo "" @echo "[*] Running Federated Queries Test..." @echo "" @$(VSQL) -f tests/federated_queries.sql 2>&1 | tee $(TMPDIR)/federated_queries.out | perl -pe 's/^vsql:[\/_:\w\.]* /vsql: /; \ diff --git a/ODBCLoader.cpp b/ODBCLoader.cpp index 95aaa76..8d691a0 100644 --- a/ODBCLoader.cpp +++ b/ODBCLoader.cpp @@ -574,9 +574,10 @@ class ODBCLoader : public UDParser { // Check "hidden" parameters __query_col_name__ and __query_col_idx__ to filter out columns if ( src_cfilter ) { - if (srvInterface.getParamReader().containsParameter("__query_col_name__")) { + if (srvInterface.getParamReader().containsParameter("__query_col_name__") && + !srvInterface.getParamReader().getStringRef("__query_col_name__").str().empty()) { if (srvInterface.getParamReader().containsParameter("__query_col_idx__")) { - colInTable = (int)colInfo.getColumnCount() ; + colInTable = (int)colInfo.getColumnCount() ; #if LOADER_DEBUG srvInterface.log("DEBUG __query_col_name__=<%s>",srvInterface.getParamReader().getStringRef("__query_col_name__").str().c_str()); srvInterface.log("DEBUG __query_col_idx__=<%s>",srvInterface.getParamReader().getStringRef("__query_col_idx__").str().c_str()); @@ -603,6 +604,9 @@ srvInterface.log("-----> External Table Columns, colInTable=<%d>", colInTable); query + " ) sq" ; } + } else { + // Plain COPY: column-filter param present but empty -> load all columns. + query = "SELECT * FROM ( " + query + " ) sq" ; } } else { @@ -665,6 +669,14 @@ srvInterface.log("-----> External Table Columns, colInTable=<%d>", colInTable); vtype = (BaseDataOID *)srvInterface.allocator->alloc(numcols * sizeof(BaseDataOID)) ; stype = (uint32 *)srvInterface.allocator->alloc(numcols * sizeof(uint32)) ; + // Plain COPY path leaves vidx empty (no column filtering). Default it to + // identity mapping (0..numcols-1) so vidx.at(i) below is valid. + if (vidx.empty()) { + for (SQLSMALLINT i = 0; i < numcols; i++) { + vidx.push_back(i); + } + } + // Set up column-data buffers // Bind to the columns in question for (SQLSMALLINT i = 0; i < numcols; i++) { From 09d41574deed3d5154c2eca2ccff5bc16331c366 Mon Sep 17 00:00:00 2001 From: SandeepDave2 Date: Tue, 14 Jul 2026 17:31:37 -0600 Subject: [PATCH 2/4] Fix plain COPY column alignment: set colInTable for pre-null loop --- ODBCLoader.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ODBCLoader.cpp b/ODBCLoader.cpp index 8d691a0..37ee72c 100644 --- a/ODBCLoader.cpp +++ b/ODBCLoader.cpp @@ -669,12 +669,13 @@ srvInterface.log("-----> External Table Columns, colInTable=<%d>", colInTable); vtype = (BaseDataOID *)srvInterface.allocator->alloc(numcols * sizeof(BaseDataOID)) ; stype = (uint32 *)srvInterface.allocator->alloc(numcols * sizeof(uint32)) ; - // Plain COPY path leaves vidx empty (no column filtering). Default it to - // identity mapping (0..numcols-1) so vidx.at(i) below is valid. + // Plain COPY leaves vidx empty. Default to identity mapping and set + // colInTable so the pre-null loop covers all columns. if (vidx.empty()) { for (SQLSMALLINT i = 0; i < numcols; i++) { vidx.push_back(i); } + colInTable = numcols; } // Set up column-data buffers From fb376a3a625ec9400865fd93ef938bda12733bb5 Mon Sep 17 00:00:00 2001 From: SandeepDave2 Date: Tue, 14 Jul 2026 17:45:37 -0600 Subject: [PATCH 3/4] Update copy_test expected output: remove stale vsql header lines --- tests/expected/copy_test.out | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/expected/copy_test.out b/tests/expected/copy_test.out index d564af8..899dded 100644 --- a/tests/expected/copy_test.out +++ b/tests/expected/copy_test.out @@ -1,5 +1,3 @@ -Timing is on. -Pager usage is off. Timing is off. SET CREATE TABLE From c852a7164aaa9abdc7aab1c5ef680e37dcf8cea4 Mon Sep 17 00:00:00 2001 From: SandeepDave2 Date: Wed, 15 Jul 2026 23:53:43 -0600 Subject: [PATCH 4/4] Addressed review comments --- ODBCLoader.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ODBCLoader.cpp b/ODBCLoader.cpp index 37ee72c..7460aaf 100644 --- a/ODBCLoader.cpp +++ b/ODBCLoader.cpp @@ -574,10 +574,11 @@ class ODBCLoader : public UDParser { // Check "hidden" parameters __query_col_name__ and __query_col_idx__ to filter out columns if ( src_cfilter ) { - if (srvInterface.getParamReader().containsParameter("__query_col_name__") && - !srvInterface.getParamReader().getStringRef("__query_col_name__").str().empty()) { - if (srvInterface.getParamReader().containsParameter("__query_col_idx__")) { - colInTable = (int)colInfo.getColumnCount() ; + // Only column-filter when the param is actually non-empty, a plain COPY sends it empty. + if (srvInterface.getParamReader().containsParameter("__query_col_name__") && + !srvInterface.getParamReader().getStringRef("__query_col_name__").str().empty()) { + if (srvInterface.getParamReader().containsParameter("__query_col_idx__")) { + colInTable = (int)colInfo.getColumnCount() ; #if LOADER_DEBUG srvInterface.log("DEBUG __query_col_name__=<%s>",srvInterface.getParamReader().getStringRef("__query_col_name__").str().c_str()); srvInterface.log("DEBUG __query_col_idx__=<%s>",srvInterface.getParamReader().getStringRef("__query_col_idx__").str().c_str());