Fix db2 params

This commit is contained in:
Eric Hare
2026-06-01 16:16:31 -07:00
parent 86fed5fe71
commit d700b5df37
2 changed files with 34 additions and 153 deletions

View File

@ -48,7 +48,13 @@ class DB2VectorStoreComponent(LCVectorStoreComponent):
ModelInput(
name="embedding_model",
display_name="Embedding Model",
info="Select an embedding model provider, or connect an Embeddings component (e.g. watsonx.ai).",
info=(
"Select an embedding model provider, or connect an Embeddings component (e.g. watsonx.ai). "
"Note: with langchain-db2 1.0.0, very high-dimension embeddings (roughly 1,500+ dimensions, "
"e.g. OpenAI text-embedding-3-large at 3072) can exceed Db2's VARCHAR bind limit during "
"insert. Prefer models around 1,024 dimensions or fewer until a newer langchain-db2 release "
"(with the CLOB fix from langchain-ai/langchain-ibm#155) is available."
),
model_type="embedding",
input_types=["Embeddings"],
required=True,
@ -174,17 +180,6 @@ class DB2VectorStoreComponent(LCVectorStoreComponent):
advanced=True,
info="Distance calculation strategy",
),
BoolInput(
name="use_bulk_insert",
display_name="Use Bulk Insert",
value=True,
advanced=True,
info=(
"Enable bulk insert using executemany() for better performance. "
"When enabled, all documents are inserted in a single batch (unlimited chunk size). "
"When disabled, uses row-by-row insert with execute() (chunk size: 1 document per call)."
),
),
]
outputs = [
@ -417,19 +412,18 @@ class DB2VectorStoreComponent(LCVectorStoreComponent):
api_key=getattr(self, "api_key", None),
)
# Log bulk insert mode
bulk_insert_enabled = getattr(self, "use_bulk_insert", True)
insert_mode = "bulk insert (executemany)" if bulk_insert_enabled else "row-by-row insert (execute)"
self.log(f"Insert mode: {insert_mode}")
# Build vector store (will automatically generate embeddings for existing empty rows)
# Build vector store (will automatically generate embeddings for existing empty rows).
# NOTE: langchain-db2's DB2VS always bulk-inserts via executemany (add_texts); there is no
# toggle for it. add_texts binds the serialized vector as a parameter, so very large
# embeddings can exceed Db2's ~32KB VARCHAR limit. The fix (a CLOB cast in
# langchain-ai/langchain-ibm#155) is merged upstream but unreleased as of langchain-db2
# 1.0.0 — see the Embedding Model input note above.
self.log(f"Connecting to DB2 table: {validated_table_name}")
vector_store = DB2VS(
client=connection,
embedding_function=embeddings,
table_name=validated_table_name,
distance_strategy=distance_strategy_map.get(self.distance_strategy, DistanceStrategy.COSINE),
use_bulk_insert=bulk_insert_enabled,
)
self.log(f"Connected to DB2 table: {validated_table_name}")

View File

@ -832,10 +832,22 @@ class TestDB2VectorStoreComponent:
):
component._add_documents_to_vector_store(mock_vector_store)
def test_bulk_insert_enabled_by_default(self, component, mock_embedding):
"""Test that bulk insert is enabled by default."""
def test_db2vs_constructed_without_use_bulk_insert(self, component, mock_embedding):
"""Regression: DB2VS must only receive kwargs the installed langchain-db2 accepts.
langchain-db2's ``DB2VS`` has no ``use_bulk_insert`` parameter (it always bulk-inserts
via ``executemany``), so passing it would raise ``TypeError`` at runtime. Because the
other tests mock ``DB2VS.__init__`` (which hides such signature mismatches), assert here
that the kwargs the component passes are a subset of the real ``DB2VS.__init__`` signature.
"""
import inspect
component.embedding_model = mock_embedding
from langchain_db2 import DB2VS
supported_params = set(inspect.signature(DB2VS.__init__).parameters) - {"self"}
with (
patch("ibm_db_dbi.connect") as mock_connect,
patch.object(component, "_add_documents_to_vector_store"),
@ -843,141 +855,16 @@ class TestDB2VectorStoreComponent:
mock_connection = MagicMock()
mock_connect.return_value = mock_connection
from langchain_db2 import DB2VS
with patch.object(DB2VS, "__init__", return_value=None) as mock_init:
component.build_vector_store()
# Verify use_bulk_insert was passed as True (default)
call_kwargs = mock_init.call_args[1]
assert call_kwargs["use_bulk_insert"] is True
def test_bulk_insert_toggle_enabled(self, component, mock_embedding):
"""Test bulk insert when explicitly enabled."""
component.embedding_model = mock_embedding
component.use_bulk_insert = True
with (
patch("ibm_db_dbi.connect") as mock_connect,
patch.object(component, "_add_documents_to_vector_store"),
):
mock_connection = MagicMock()
mock_connect.return_value = mock_connection
from langchain_db2 import DB2VS
with patch.object(DB2VS, "__init__", return_value=None) as mock_init:
component.build_vector_store()
# Verify use_bulk_insert was passed as True
call_kwargs = mock_init.call_args[1]
assert call_kwargs["use_bulk_insert"] is True
def test_bulk_insert_toggle_disabled(self, component, mock_embedding):
"""Test bulk insert when explicitly disabled."""
component.embedding_model = mock_embedding
component.use_bulk_insert = False
with (
patch("ibm_db_dbi.connect") as mock_connect,
patch.object(component, "_add_documents_to_vector_store"),
):
mock_connection = MagicMock()
mock_connect.return_value = mock_connection
from langchain_db2 import DB2VS
with patch.object(DB2VS, "__init__", return_value=None) as mock_init:
component.build_vector_store()
# Verify use_bulk_insert was passed as False
call_kwargs = mock_init.call_args[1]
assert call_kwargs["use_bulk_insert"] is False
def test_bulk_insert_with_multiple_documents(self, component, mock_embedding):
"""Test bulk insert with multiple documents."""
component.embedding_model = mock_embedding
component.use_bulk_insert = True
component.ingest_data = [
Data(text="Document 1"),
Data(text="Document 2"),
Data(text="Document 3"),
Data(text="Document 4"),
Data(text="Document 5"),
]
with (
patch("ibm_db_dbi.connect") as mock_connect,
):
mock_connection = MagicMock()
mock_cursor = MagicMock()
mock_connection.cursor.return_value = mock_cursor
mock_connect.return_value = mock_connection
from langchain_db2 import DB2VS
with (
patch.object(DB2VS, "__init__", return_value=None),
patch.object(DB2VS, "add_documents") as mock_add_docs,
):
vector_store = component.build_vector_store()
component._add_documents_to_vector_store(vector_store)
# Verify documents were added
if mock_add_docs.called:
added_docs = mock_add_docs.call_args[0][0]
assert len(added_docs) == 5, "All 5 documents should be added"
def test_bulk_insert_logging(self, component, mock_embedding):
"""Test that bulk insert mode is logged correctly."""
component.embedding_model = mock_embedding
component.use_bulk_insert = True
with (
patch("ibm_db_dbi.connect") as mock_connect,
patch.object(component, "_add_documents_to_vector_store"),
):
mock_connection = MagicMock()
mock_connect.return_value = mock_connection
from langchain_db2 import DB2VS
with patch.object(DB2VS, "__init__", return_value=None), patch.object(component, "log") as mock_log:
component.build_vector_store()
messages = [str(call.args[0]).lower() for call in mock_log.call_args_list]
assert any("bulk insert" in message or "executemany" in message for message in messages)
def test_row_by_row_insert_logging(self, component, mock_embedding):
"""Test that row-by-row insert mode is logged correctly."""
component.embedding_model = mock_embedding
component.use_bulk_insert = False
with (
patch("ibm_db_dbi.connect") as mock_connect,
patch.object(component, "_add_documents_to_vector_store"),
):
mock_connection = MagicMock()
mock_connect.return_value = mock_connection
from langchain_db2 import DB2VS
with patch.object(DB2VS, "__init__", return_value=None), patch.object(component, "log") as mock_log:
component.build_vector_store()
messages = [str(call.args[0]).lower() for call in mock_log.call_args_list]
assert any("row-by-row" in message or "execute" in message for message in messages)
def test_bulk_insert_input_exists(self, component):
"""Test that use_bulk_insert input is defined in component."""
# Check that the input exists in the component's inputs
input_names = [inp.name for inp in component.inputs]
assert "use_bulk_insert" in input_names, "use_bulk_insert input should be defined"
# Find the input and verify its properties
bulk_insert_input = next(inp for inp in component.inputs if inp.name == "use_bulk_insert")
assert bulk_insert_input.value is True, "Default value should be True"
assert bulk_insert_input.advanced is True, "Should be an advanced setting"
passed_kwargs = set(mock_init.call_args.kwargs)
assert "use_bulk_insert" not in passed_kwargs, (
"DB2VS no longer accepts `use_bulk_insert`; do not pass it to the constructor."
)
assert passed_kwargs <= supported_params, (
f"DB2VS called with unsupported kwargs: {sorted(passed_kwargs - supported_params)}"
)
# Made with Bob