diff --git a/client/src/com/aerospike/client/AerospikeClient.java b/client/src/com/aerospike/client/AerospikeClient.java index f5ffee2c7..9f6e7a992 100644 --- a/client/src/com/aerospike/client/AerospikeClient.java +++ b/client/src/com/aerospike/client/AerospikeClient.java @@ -1786,6 +1786,9 @@ public final Record[] get(BatchPolicy policy, Key[] keys, String... binNames) policy = batchPolicyDefault; } + int readAttr = (binNames == null || binNames.length == 0)? + Command.INFO1_READ | Command.INFO1_GET_ALL : Command.INFO1_READ; + Record[] records = new Record[keys.length]; try { @@ -1802,7 +1805,7 @@ public final Record[] get(BatchPolicy policy, Key[] keys, String... binNames) } else { commands[count++] = new Batch.GetArrayCommand( - cluster, bn, policy, keys, binNames, null, records, Command.INFO1_READ, false, status); + cluster, bn, policy, keys, binNames, null, records, readAttr, false, status); } } BatchExecutor.execute(cluster, policy, commands, status); @@ -1844,6 +1847,9 @@ public final void get(EventLoop eventLoop, RecordArrayListener listener, BatchPo policy = batchPolicyDefault; } + int readAttr = (binNames == null || binNames.length == 0)? + Command.INFO1_READ | Command.INFO1_GET_ALL : Command.INFO1_READ; + Record[] records = new Record[keys.length]; AsyncBatchExecutor.GetArray executor = new AsyncBatchExecutor.GetArray( eventLoop, cluster, listener, keys, records); @@ -1859,7 +1865,7 @@ public final void get(EventLoop eventLoop, RecordArrayListener listener, BatchPo } else { commands[count++] = new AsyncBatch.GetArrayCommand( - executor, bn, policy, keys, binNames, null, records, Command.INFO1_READ, false); + executor, bn, policy, keys, binNames, null, records, readAttr, false); } } executor.execute(commands); @@ -1896,6 +1902,9 @@ public final void get(EventLoop eventLoop, RecordSequenceListener listener, Batc policy = batchPolicyDefault; } + int readAttr = (binNames == null || binNames.length == 0)? + Command.INFO1_READ | Command.INFO1_GET_ALL : Command.INFO1_READ; + AsyncBatchExecutor.GetSequence executor = new AsyncBatchExecutor.GetSequence(eventLoop, cluster, listener); List bns = BatchNodeList.generate(cluster, policy, keys, null, false, executor); AsyncCommand[] commands = new AsyncCommand[bns.size()]; @@ -1909,7 +1918,7 @@ public final void get(EventLoop eventLoop, RecordSequenceListener listener, Batc } else { commands[count++] = new AsyncBatch.GetSequenceCommand( - executor, bn, policy, keys, binNames, null, listener, Command.INFO1_READ, false); + executor, bn, policy, keys, binNames, null, listener, readAttr, false); } } executor.execute(commands); diff --git a/client/src/com/aerospike/client/command/BatchAttr.java b/client/src/com/aerospike/client/command/BatchAttr.java index 487a742d0..7f063537e 100644 --- a/client/src/com/aerospike/client/command/BatchAttr.java +++ b/client/src/com/aerospike/client/command/BatchAttr.java @@ -48,7 +48,7 @@ public BatchAttr(Policy policy, int rattr) { public BatchAttr(Policy policy, int rattr, Operation[] ops) { setRead(policy); - this.readAttr |= rattr; + this.readAttr = rattr; if (ops != null) { adjustRead(ops); diff --git a/client/src/com/aerospike/client/command/Command.java b/client/src/com/aerospike/client/command/Command.java index 0e573594c..e1506f481 100644 --- a/client/src/com/aerospike/client/command/Command.java +++ b/client/src/com/aerospike/client/command/Command.java @@ -242,7 +242,17 @@ public final void setExists(Policy policy, Key key) { end(); } - private final void setRead(Policy policy, Key key) { + public final void setRead(Policy policy, Key key, String[] binNames) { + int readAttr = Command.INFO1_READ; + int opCount = 0; + + if (binNames != null && binNames.length > 0) { + opCount = binNames.length; + } + else { + readAttr |= Command.INFO1_GET_ALL; + } + begin(); int fieldCount = estimateKeySize(policy, key); @@ -250,45 +260,27 @@ private final void setRead(Policy policy, Key key) { dataOffset += policy.filterExp.size(); fieldCount++; } + + if (opCount != 0) { + for (String binName : binNames) { + estimateOperationSize(binName); + } + } + sizeBuffer(); - writeHeaderRead(policy, serverTimeout, Command.INFO1_READ | Command.INFO1_GET_ALL, 0, 0, fieldCount, 0); + writeHeaderRead(policy, serverTimeout, readAttr, 0, 0, fieldCount, opCount); writeKey(policy, key); if (policy.filterExp != null) { policy.filterExp.write(this); } - end(); - } - - public final void setRead(Policy policy, Key key, String[] binNames) { - if (binNames != null) { - begin(); - int fieldCount = estimateKeySize(policy, key); - - if (policy.filterExp != null) { - dataOffset += policy.filterExp.size(); - fieldCount++; - } - - for (String binName : binNames) { - estimateOperationSize(binName); - } - sizeBuffer(); - writeHeaderRead(policy, serverTimeout, Command.INFO1_READ, 0, 0, fieldCount, binNames.length); - writeKey(policy, key); - - if (policy.filterExp != null) { - policy.filterExp.write(this); - } + if (opCount != 0) { for (String binName : binNames) { writeOperation(binName, Operation.Type.READ); } - end(); - } - else { - setRead(policy, key); } + end(); } public final void setRead(Policy policy, BatchRead br) { @@ -852,7 +844,13 @@ public final void setBatchOperate( } if (br.binNames != null) { - writeBatchBinNames(key, br.binNames, attr, attr.filterExp); + if (br.binNames.length > 0) { + writeBatchBinNames(key, br.binNames, attr, attr.filterExp); + } + else { + attr.adjustRead(true); + writeBatchRead(key, attr, attr.filterExp, 0); + } } else if (br.ops != null) { attr.adjustRead(br.ops); diff --git a/proxy/src/com/aerospike/client/proxy/AerospikeClientProxy.java b/proxy/src/com/aerospike/client/proxy/AerospikeClientProxy.java index 7274c0f5f..889e1c502 100644 --- a/proxy/src/com/aerospike/client/proxy/AerospikeClientProxy.java +++ b/proxy/src/com/aerospike/client/proxy/AerospikeClientProxy.java @@ -1335,7 +1335,9 @@ public void get(EventLoop eventLoop, RecordArrayListener listener, BatchPolicy p policy = batchPolicyDefault; } - CommandProxy command = new BatchProxy.GetArrayCommand(executor, policy, listener, keys, binNames, null, Command.INFO1_READ, false); + int readAttr = (binNames == null || binNames.length == 0)? Command.INFO1_READ | Command.INFO1_GET_ALL : Command.INFO1_READ; + + CommandProxy command = new BatchProxy.GetArrayCommand(executor, policy, listener, keys, binNames, null, readAttr, false); command.execute(); } @@ -1363,7 +1365,9 @@ public void get(EventLoop eventLoop, RecordSequenceListener listener, BatchPolic policy = batchPolicyDefault; } - CommandProxy command = new BatchProxy.GetSequenceCommand(executor, policy, listener, keys, binNames, null, Command.INFO1_READ, false); + int readAttr = (binNames == null || binNames.length == 0)? Command.INFO1_READ | Command.INFO1_GET_ALL : Command.INFO1_READ; + + CommandProxy command = new BatchProxy.GetSequenceCommand(executor, policy, listener, keys, binNames, null, readAttr, false); command.execute(); } diff --git a/test/src/com/aerospike/test/sync/basic/TestBatch.java b/test/src/com/aerospike/test/sync/basic/TestBatch.java index 90afd5765..82b7083ed 100644 --- a/test/src/com/aerospike/test/sync/basic/TestBatch.java +++ b/test/src/com/aerospike/test/sync/basic/TestBatch.java @@ -144,6 +144,30 @@ public void batchReads () { } } + @Test + public void batchReadsEmptyBinNames() { + Key[] keys = new Key[Size]; + for (int i = 0; i < Size; i++) { + keys[i] = new Key(args.namespace, args.set, KeyPrefix + (i + 1)); + } + + String[] binNames = new String[] {}; + Record[] records = client.get(null, keys, binNames); + assertEquals(Size, records.length); + + for (int i = 0; i < records.length; i++) { + Key key = keys[i]; + Record record = records[i]; + + if (i != 5) { + assertBinEqual(key, record, BinName, ValuePrefix + (i + 1)); + } + else { + assertBinEqual(key, record, BinName, i + 1); + } + } + } + @Test public void batchReadHeaders () { Key[] keys = new Key[Size]; @@ -168,7 +192,7 @@ public void batchReadHeaders () { } @Test - public void batchReadComplex () { + public void batchReadComplex() { // Batch allows multiple namespaces in one call, but example test environment may only have one namespace. // bin * 8 @@ -179,7 +203,7 @@ public void batchReadComplex () { List records = new ArrayList(); records.add(new BatchRead(new Key(args.namespace, args.set, KeyPrefix + 1), bins)); records.add(new BatchRead(new Key(args.namespace, args.set, KeyPrefix + 2), true)); - records.add(new BatchRead(new Key(args.namespace, args.set, KeyPrefix + 3), true)); + records.add(new BatchRead(new Key(args.namespace, args.set, KeyPrefix + 3), new String[] {})); records.add(new BatchRead(new Key(args.namespace, args.set, KeyPrefix + 4), false)); records.add(new BatchRead(new Key(args.namespace, args.set, KeyPrefix + 5), true)); records.add(new BatchRead(new Key(args.namespace, args.set, KeyPrefix + 6), ops)); diff --git a/test/src/com/aerospike/test/sync/basic/TestPutGet.java b/test/src/com/aerospike/test/sync/basic/TestPutGet.java index e2f99cd42..58830abee 100644 --- a/test/src/com/aerospike/test/sync/basic/TestPutGet.java +++ b/test/src/com/aerospike/test/sync/basic/TestPutGet.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 Aerospike, Inc. + * Copyright 2012-2024 Aerospike, Inc. * * Portions may be licensed to Aerospike, Inc. under one or more contributor * license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0. @@ -41,6 +41,11 @@ public void putGet() { Record record = client.get(null, key); assertBinEqual(key, record, bin1); assertBinEqual(key, record, bin2); + + // Test empty binNames array. + record = client.get(null, key, new String[] {}); + assertBinEqual(key, record, bin1); + assertBinEqual(key, record, bin2); } @Test diff --git a/test/src/com/aerospike/test/sync/basic/TestScan.java b/test/src/com/aerospike/test/sync/basic/TestScan.java index d0b3e1762..c6a29289f 100644 --- a/test/src/com/aerospike/test/sync/basic/TestScan.java +++ b/test/src/com/aerospike/test/sync/basic/TestScan.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 Aerospike, Inc. + * Copyright 2012-2024 Aerospike, Inc. * * Portions may be licensed to Aerospike, Inc. under one or more contributor * license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0. @@ -35,6 +35,10 @@ public class TestScan extends TestSync implements ScanCallback { public void scanParallel() { ScanPolicy policy = new ScanPolicy(); client.scanAll(policy, args.namespace, args.set, this); + + // Test empty binNames. + String[] binNames = new String[] {}; + client.scanAll(policy, args.namespace, args.set, this, binNames); } @Test diff --git a/test/src/com/aerospike/test/sync/query/TestQueryString.java b/test/src/com/aerospike/test/sync/query/TestQueryString.java index 92a2ea96a..8ef779f0c 100644 --- a/test/src/com/aerospike/test/sync/query/TestQueryString.java +++ b/test/src/com/aerospike/test/sync/query/TestQueryString.java @@ -95,4 +95,33 @@ public void queryString() { rs.close(); } } + + @Test + public void queryStringEmptyBinName() { + String filter = valuePrefix + 3; + + Statement stmt = new Statement(); + stmt.setNamespace(args.namespace); + stmt.setSetName(args.set); + stmt.setBinNames(new String[] {}); + stmt.setFilter(Filter.equal(binName, filter)); + + RecordSet rs = client.query(null, stmt); + + try { + int count = 0; + + while (rs.next()) { + Record record = rs.getRecord(); + String result = record.getString(binName); + assertEquals(filter, result); + count++; + } + + assertNotEquals(0, count); + } + finally { + rs.close(); + } + } }