From 22a49ba82322c5517a941732e85e71c8917ad53b Mon Sep 17 00:00:00 2001 From: diparthaspike Date: Tue, 18 Aug 2026 11:33:27 +0530 Subject: [PATCH 1/4] [CLIENT-2479]: bump c client, add tests and docs --- aerospike-client-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aerospike-client-c b/aerospike-client-c index 9f3621e9f2..8025c2a0fc 160000 --- a/aerospike-client-c +++ b/aerospike-client-c @@ -1 +1 @@ -Subproject commit 9f3621e9f23bed3fcfe89cc986aced58f6d8903a +Subproject commit 8025c2a0fc28b2cab2f126821c2f3fbe429e9600 From a2e277483c71fd7f4becfc27a48e2df12f08ef11 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Fri, 14 Aug 2026 08:58:05 -0700 Subject: [PATCH 2/4] Add test cases that verify that the C client currently does not return an error if both write operations and a record UDF are added to a background query/scan. --- test/new_tests/test_query_execute_background.py | 14 ++++++++++++++ test/new_tests/test_scan_execute_background.py | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/test/new_tests/test_query_execute_background.py b/test/new_tests/test_query_execute_background.py index 270134adad..b5e2042b95 100644 --- a/test/new_tests/test_query_execute_background.py +++ b/test/new_tests/test_query_execute_background.py @@ -378,3 +378,17 @@ def test_add_ops_then_select_bins_then_bg_query(self, query): records = query.results() for _, _, bins in records: assert bins[BIN_NAME] == 3 + + def test_add_ops_then_apply(self, query): + query.add_ops(WRITE_OPS) + test_bin = "tz" + query.apply(TEST_UDF_MODULE, TEST_UDF_FUNCTION, [test_bin]) + + query.execute_background() + + def test_apply_then_add_ops(self, query): + test_bin = "tz" + query.apply(TEST_UDF_MODULE, TEST_UDF_FUNCTION, [test_bin]) + query.add_ops(WRITE_OPS) + + query.execute_background() diff --git a/test/new_tests/test_scan_execute_background.py b/test/new_tests/test_scan_execute_background.py index 9eb906835b..6af836f524 100644 --- a/test/new_tests/test_scan_execute_background.py +++ b/test/new_tests/test_scan_execute_background.py @@ -379,3 +379,17 @@ def test_add_ops_then_select_bins_then_bg_query(self, scan_obj): records = scan2.results() for _, _, bins in records: assert bins[BIN_NAME] == 3 + + def test_add_ops_then_apply(self, scan_obj): + scan_obj.add_ops(WRITE_OPS) + test_bin = "tz" + scan_obj.apply(TEST_UDF_MODULE, TEST_UDF_FUNCTION, [test_bin]) + + scan_obj.execute_background() + + def test_apply_then_add_ops(self, scan_obj): + test_bin = "tz" + scan_obj.apply(TEST_UDF_MODULE, TEST_UDF_FUNCTION, [test_bin]) + scan_obj.add_ops(WRITE_OPS) + + scan_obj.execute_background() From d5db623fc282a3b594768c8387d0e18943662906 Mon Sep 17 00:00:00 2001 From: diparthaspike Date: Tue, 18 Aug 2026 11:48:04 +0530 Subject: [PATCH 3/4] Add tests --- test/new_tests/test_query_execute_background.py | 8 ++++++-- test/new_tests/test_scan_execute_background.py | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/test/new_tests/test_query_execute_background.py b/test/new_tests/test_query_execute_background.py index b5e2042b95..28324a343f 100644 --- a/test/new_tests/test_query_execute_background.py +++ b/test/new_tests/test_query_execute_background.py @@ -384,11 +384,15 @@ def test_add_ops_then_apply(self, query): test_bin = "tz" query.apply(TEST_UDF_MODULE, TEST_UDF_FUNCTION, [test_bin]) - query.execute_background() + with pytest.raises(exception.ParamError) as excinfo: + query.execute_background() + assert excinfo.value.msg == "Cannot combine query operations with aggregation" def test_apply_then_add_ops(self, query): test_bin = "tz" query.apply(TEST_UDF_MODULE, TEST_UDF_FUNCTION, [test_bin]) query.add_ops(WRITE_OPS) - query.execute_background() + with pytest.raises(exception.ParamError) as excinfo: + query.execute_background() + assert excinfo.value.msg == "Cannot combine query operations with aggregation" diff --git a/test/new_tests/test_scan_execute_background.py b/test/new_tests/test_scan_execute_background.py index 6af836f524..1a90d90ca4 100644 --- a/test/new_tests/test_scan_execute_background.py +++ b/test/new_tests/test_scan_execute_background.py @@ -385,11 +385,15 @@ def test_add_ops_then_apply(self, scan_obj): test_bin = "tz" scan_obj.apply(TEST_UDF_MODULE, TEST_UDF_FUNCTION, [test_bin]) - scan_obj.execute_background() + with pytest.raises(exception.ParamError) as excinfo: + scan_obj.execute_background() + assert excinfo.value.msg == "Cannot combine scan operations with a UDF" def test_apply_then_add_ops(self, scan_obj): test_bin = "tz" scan_obj.apply(TEST_UDF_MODULE, TEST_UDF_FUNCTION, [test_bin]) scan_obj.add_ops(WRITE_OPS) - scan_obj.execute_background() + with pytest.raises(exception.ParamError) as excinfo: + scan_obj.execute_background() + assert excinfo.value.msg == "Cannot combine scan operations with a UDF" From 5e55e9488ffee42dd8c573eda286b78162ea9a2b Mon Sep 17 00:00:00 2001 From: diparthaspike Date: Tue, 18 Aug 2026 11:53:33 +0530 Subject: [PATCH 4/4] [CLIENT-2479]: document that add_ops() and apply() are mutually exclusive Query/Scan execute_background() now raises ParamError (via the C client fix) if both a UDF (apply()) and write operations (add_ops()) have been set on the same object. Document this at apply(), add_ops(), and execute_background() for both Query and Scan, plus in query.rst's Query Aggregations overview section. --- doc/query.rst | 13 +++++++++++++ doc/scan.rst | 13 +++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/doc/query.rst b/doc/query.rst index 4a79bbc152..dffa5922d1 100755 --- a/doc/query.rst +++ b/doc/query.rst @@ -57,6 +57,10 @@ A `stream UDF `_. @@ -496,6 +503,9 @@ Assume this boilerplate code is run before all examples below: If there are selected bins in this Query object via :meth:`~Query.select`, those selected bins will be ignored during the query. + This method cannot be used together with :meth:`~aerospike.Query.apply` on the same :class:`~aerospike.Query` + object — see :meth:`~aerospike.Query.execute_background`. + :param ops: `list` A list of operations generated from :ref:`aerospike_operation_helpers.operations`. .. note:: @@ -506,6 +516,9 @@ Assume this boilerplate code is run before all examples below: Execute a record UDF or write operations on records found by the query in the background. This method returns before the query has completed. A UDF or a list of write operations must have been added to the query with :meth:`Query.apply` or :meth:`Query.add_ops` respectively. + :meth:`Query.apply` and :meth:`Query.add_ops` cannot both be used on the same :class:`~aerospike.Query` object. + Calling this method after both have been set will raise a :exc:`~aerospike.exception.ParamError`. + :param dict policy: optional :ref:`aerospike_write_policies`. :return: a job ID that can be used with :meth:`~aerospike.Client.job_info` to track the status of the :py:data:`aerospike.JOB_QUERY` , as it runs in the background. diff --git a/doc/scan.rst b/doc/scan.rst index 6dce2c9fb6..9973e6a8be 100755 --- a/doc/scan.rst +++ b/doc/scan.rst @@ -71,6 +71,9 @@ Methods If you need to use an unsupported type, (e.g. set or tuple) you must use your own serializer. :return: one of the supported types, :class:`int`, :class:`str`, :class:`float` (double), :class:`list`, :class:`dict` (map), :class:`bytearray` (bytes), :class:`bool`. + This method cannot be used together with :meth:`~aerospike.Scan.add_ops` on the same :class:`~aerospike.Scan` + object — see :meth:`~aerospike.Scan.execute_background`. + .. seealso:: `Developing Record UDFs `_ @@ -84,6 +87,9 @@ Methods For foreground scans, only read operations are allowed. :meth:`Scan.foreach` and :meth:`Scan.results` will raise a :py:exc:`~aerospike.exception.ParamError` if a write operation has been set with :meth:`Scan.add_ops`. + This method cannot be used together with :meth:`~aerospike.Scan.apply` on the same :class:`~aerospike.Scan` + object — see :meth:`~aerospike.Scan.execute_background`. + :param ops: `list` A list of write operations generated by the aerospike_helpers e.g. list_operations, map_operations, etc. .. note:: @@ -297,8 +303,11 @@ Methods .. method:: execute_background([, policy]) - Execute a record UDF on records found by the scan in the background. This method returns before the scan has completed. - A UDF can be added to the scan with :meth:`Scan.apply`. + Execute a record UDF or write operations on records found by the scan in the background. This method returns before the scan has completed. + A UDF or a list of write operations must have been added to the scan with :meth:`Scan.apply` or :meth:`Scan.add_ops` respectively. + + :meth:`Scan.apply` and :meth:`Scan.add_ops` cannot both be used on the same :class:`~aerospike.Scan` object. + Calling this method after both have been set will raise a :exc:`~aerospike.exception.ParamError`. :param dict policy: optional :ref:`aerospike_write_policies`.