From d700b5df37d25432dbfbab0f182e6d1122a623a8 Mon Sep 17 00:00:00 2001 From: Eric Hare Date: Mon, 1 Jun 2026 16:16:31 -0700 Subject: [PATCH] Fix db2 params --- .../src/lfx_ibm/components/ibm/db2_vector.py | 32 ++-- src/bundles/ibm/tests/test_db2_vector.py | 155 +++--------------- 2 files changed, 34 insertions(+), 153 deletions(-) diff --git a/src/bundles/ibm/src/lfx_ibm/components/ibm/db2_vector.py b/src/bundles/ibm/src/lfx_ibm/components/ibm/db2_vector.py index 4ee5177574..9307280cfb 100644 --- a/src/bundles/ibm/src/lfx_ibm/components/ibm/db2_vector.py +++ b/src/bundles/ibm/src/lfx_ibm/components/ibm/db2_vector.py @@ -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}") diff --git a/src/bundles/ibm/tests/test_db2_vector.py b/src/bundles/ibm/tests/test_db2_vector.py index 80ecdb25d7..4cfd348e05 100644 --- a/src/bundles/ibm/tests/test_db2_vector.py +++ b/src/bundles/ibm/tests/test_db2_vector.py @@ -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