Skip to content

Commit 03c11f6

Browse files
committed
Bug#32959894 CLUSTERJ PARTITION KEY SCRATCH BUFFER SIZE TOO SMALL
Contributed by: Mikael Ronström ClusterJ uses a scratch buffer for primary key hash calculations which is limited to 10000 bytes. This is too small in some cases. The solution is to malloc the buffer in computeHash if the buffer isn't big enough. This patch contains a test for this bug that ensures that the primary key requires a buffer larger than 10000 bytes. Contributed patch was modified as: - update comments for startTransaction and computeHash - test with Varchar columns instead of Longvarchar - revert changes to tests Bug17200163Test and ConversationSummary - replaced tabs with spaces and remove dead code Change-Id: Ifb8d82b167e91fd48416186938936361bcb0bd67
1 parent 8bee07c commit 03c11f6

File tree

7 files changed

+400
-21
lines changed

7 files changed

+400
-21
lines changed

mysql-test/suite/ndb/r/clusterj.result

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ DROP TABLE datetypes;
3535
DROP TABLE decimaltypes;
3636
DROP TABLE dn2id;
3737
DROP TABLE doubletypes;
38+
DROP TABLE dynamicstringpks;
3839
DROP TABLE floattypes;
3940
DROP TABLE hashpk;
4041
DROP TABLE hope;

mysql-test/suite/ndb/t/clusterj.test

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ DROP TABLE datetypes;
6464
DROP TABLE decimaltypes;
6565
DROP TABLE dn2id;
6666
DROP TABLE doubletypes;
67+
DROP TABLE dynamicstringpks;
6768
DROP TABLE floattypes;
6869
DROP TABLE hashpk;
6970
DROP TABLE hope;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates.
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License, version 2.0,
6+
* as published by the Free Software Foundation.
7+
*
8+
* This program is also distributed with certain software (including
9+
* but not limited to OpenSSL) that is licensed under separate terms,
10+
* as designated in a particular file or component or in included license
11+
* documentation. The authors of MySQL hereby grant you an additional
12+
* permission to link the program and your derivative works with the
13+
* separately licensed software that they have included with MySQL.
14+
*
15+
* This program is distributed in the hope that it will be useful,
16+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
* GNU General Public License, version 2.0, for more details.
19+
*
20+
* You should have received a copy of the GNU General Public License
21+
* along with this program; if not, write to the Free Software
22+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23+
*/
24+
25+
package testsuite.clusterj;
26+
27+
import java.util.ArrayList;
28+
import java.util.List;
29+
30+
import com.mysql.clusterj.DynamicObject;
31+
import testsuite.clusterj.model.DynamicStringPKs;
32+
33+
public class DynamicStringPKTest extends AbstractClusterJTest {
34+
35+
protected int NUMBER_OF_INSTANCES = 15;
36+
protected List<DynamicStringPKs> instances = new ArrayList<DynamicStringPKs>();
37+
38+
@Override
39+
public void localSetUp() {
40+
createSessionFactory();
41+
session = sessionFactory.getSession();
42+
tx = session.currentTransaction();
43+
}
44+
45+
public void test() {
46+
run(DynamicStringPK.class);
47+
failOnError();
48+
}
49+
50+
public void run(Class<? extends DynamicStringPKs> cls) {
51+
deleteAll(cls);
52+
createInstances(cls);
53+
insert();
54+
find(cls);
55+
update(cls);
56+
delete(cls);
57+
}
58+
59+
public static class DynamicStringPK extends DynamicStringPKs {
60+
@Override
61+
public String table() {
62+
return "dynamicstringpks";
63+
}
64+
}
65+
66+
protected void deleteAll(Class<? extends DynamicStringPKs> cls) {
67+
try {
68+
tx.begin();
69+
session.deletePersistentAll(cls);
70+
tx.commit();
71+
} catch (Throwable t) {
72+
// ignore errors while deleting
73+
}
74+
}
75+
76+
/** Insert all instances.
77+
*/
78+
protected void insert() {
79+
session.makePersistentAll(instances);
80+
}
81+
82+
/** Find all instances.
83+
*/
84+
protected void find(Class<? extends DynamicStringPKs> cls) {
85+
String where = "find " + cls.getName();
86+
for (int i = 0; i < NUMBER_OF_INSTANCES; ++i) {
87+
tx.begin();
88+
String key = getPK(i);
89+
DynamicStringPKs dynObj = (DynamicStringPKs) session.newInstance(cls);
90+
dynObj.setKey1(key);
91+
dynObj.setKey2(key);
92+
dynObj.setKey3(key);
93+
dynObj.setKey4(i);
94+
dynObj.setKey5(key);
95+
dynObj.setKey6(i);
96+
dynObj.setKey7(key);
97+
DynamicStringPKs result = session.load(dynObj);
98+
session.flush();
99+
tx.commit();
100+
verify(where, result, i, false);
101+
}
102+
}
103+
104+
/** Blind update every fourth instance.
105+
*/
106+
protected void update(Class<? extends DynamicStringPKs> cls) {
107+
// update the instances
108+
String where = "update before " + cls.getName();
109+
for (int i = 0; i < NUMBER_OF_INSTANCES; ++i) {
110+
if (0 == i % 4) {
111+
DynamicStringPKs instance = createInstance(cls, i);
112+
instance.setName(getValue(NUMBER_OF_INSTANCES - i));
113+
session.savePersistent(instance);
114+
verify(where, instance, i, true);
115+
}
116+
}
117+
// verify the updated instances
118+
where = "update after " + cls.getName();
119+
for (int i = 0; i < NUMBER_OF_INSTANCES; ++i) {
120+
if (0 == i % 4) {
121+
tx.begin();
122+
String key = getPK(i);
123+
DynamicStringPKs dynObj = (DynamicStringPKs) session.newInstance(cls);
124+
dynObj.setKey1(key);
125+
dynObj.setKey2(key);
126+
dynObj.setKey3(key);
127+
dynObj.setKey4(i);
128+
dynObj.setKey5(key);
129+
dynObj.setKey6(i);
130+
dynObj.setKey7(key);
131+
DynamicStringPKs result = session.load(dynObj);
132+
session.flush();
133+
tx.commit();
134+
verify(where, result, i, true);
135+
}
136+
}
137+
}
138+
139+
/** Blind delete every fifth instance.
140+
*/
141+
protected void delete(Class<? extends DynamicStringPKs> cls) {
142+
// delete the instances
143+
for (int i = 0; i < NUMBER_OF_INSTANCES; ++i) {
144+
if (0 == i % 5) {
145+
DynamicStringPKs instance = createInstance(cls, i);
146+
session.deletePersistent(instance);
147+
}
148+
}
149+
// verify they have been deleted
150+
for (int i = 0; i < NUMBER_OF_INSTANCES; ++i) {
151+
if (0 == i % 5) {
152+
tx.begin();
153+
String key = getPK(i);
154+
DynamicStringPKs dynObj = (DynamicStringPKs) session.newInstance(cls);
155+
dynObj.setKey1(key);
156+
dynObj.setKey2(key);
157+
dynObj.setKey3(key);
158+
dynObj.setKey4(i);
159+
dynObj.setKey5(key);
160+
dynObj.setKey6(i);
161+
dynObj.setKey7(key);
162+
DynamicStringPKs result = session.load(dynObj);
163+
session.flush();
164+
tx.commit();
165+
Boolean found_object = session.found(dynObj);
166+
if (!found_object || found_object == null)
167+
{
168+
result = null;
169+
}
170+
errorIfNotEqual("Failed to delete instance: " + i, null, result);
171+
}
172+
}
173+
}
174+
175+
protected void createInstances(Class<? extends DynamicStringPKs> cls) {
176+
instances.clear();
177+
for (int i = 0; i < NUMBER_OF_INSTANCES; ++i) {
178+
DynamicStringPKs instance = createInstance(cls, i);
179+
if (getDebug()) System.out.println(toString(instance));
180+
instances.add(instance);
181+
}
182+
}
183+
184+
/** Create an instance of DynamicStringPKs.
185+
* @param index the index to use to generate data
186+
* @return the instance
187+
*/
188+
protected DynamicStringPKs createInstance(Class<?extends DynamicStringPKs> cls, int index) {
189+
DynamicStringPKs instance = session.newInstance(cls);
190+
instance.setKey1(getPK(index));
191+
instance.setKey2(getPK(index));
192+
instance.setKey3(getPK(index));
193+
instance.setKey4(index);
194+
instance.setKey5(getPK(index));
195+
instance.setKey6(index);
196+
instance.setKey7(getPK(index));
197+
instance.setNumber(index);
198+
instance.setName(getValue(index));
199+
return instance;
200+
}
201+
202+
protected String toString(DynamicStringPKs instance) {
203+
StringBuffer result = new StringBuffer(instance.getClass().getName());
204+
result.append("[");
205+
result.append(instance.getKey1());
206+
result.append(", \"");
207+
result.append(instance.getKey2());
208+
result.append(", \"");
209+
result.append(instance.getKey3());
210+
result.append(", \"");
211+
result.append(instance.getKey4());
212+
result.append(", \"");
213+
result.append(instance.getKey5());
214+
result.append(", \"");
215+
result.append(instance.getKey6());
216+
result.append(", \"");
217+
result.append(instance.getKey7());
218+
result.append("]: ");
219+
result.append(instance.getNumber());
220+
result.append(", \"");
221+
result.append(instance.getName());
222+
result.append("\".");
223+
return result.toString();
224+
}
225+
226+
protected String getPK(int index) {
227+
String result = "Text............. " + index;
228+
return result;
229+
}
230+
231+
protected String getValue(int index) {
232+
return "Value " + index;
233+
}
234+
235+
protected void verify(String where, DynamicStringPKs instance, int index, boolean updated) {
236+
errorIfNotEqual(where + "id failed", getPK(index), instance.getKey1());
237+
errorIfNotEqual(where + "number failed", index, instance.getNumber());
238+
if (updated) {
239+
errorIfNotEqual(where + " Value failed", getValue(NUMBER_OF_INSTANCES - index), instance.getName());
240+
} else {
241+
errorIfNotEqual(where + " Value failed", getValue(index), instance.getName());
242+
243+
}
244+
}
245+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates.
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License, version 2.0,
6+
* as published by the Free Software Foundation.
7+
*
8+
* This program is also distributed with certain software (including
9+
* but not limited to OpenSSL) that is licensed under separate terms,
10+
* as designated in a particular file or component or in included license
11+
* documentation. The authors of MySQL hereby grant you an additional
12+
* permission to link the program and your derivative works with the
13+
* separately licensed software that they have included with MySQL.
14+
*
15+
* This program is distributed in the hope that it will be useful,
16+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
* GNU General Public License, version 2.0, for more details.
19+
*
20+
* You should have received a copy of the GNU General Public License
21+
* along with this program; if not, write to the Free Software
22+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23+
*/
24+
25+
package testsuite.clusterj.model;
26+
27+
import com.mysql.clusterj.DynamicObject;
28+
29+
/** Schema
30+
*
31+
drop table if exists dynamicstringpks;
32+
create table dynamicstringpks (
33+
key1 varchar(85) collate utf8_unicode_ci not null,
34+
key2 varchar(85) collate utf8_unicode_ci not null,
35+
key3 varchar(85) collate utf8_unicode_ci not null,
36+
key4 bigint not null,
37+
key5 varchar(85) collate utf8_unicode_ci not null,
38+
key6 bigint not null,
39+
key7 varchar(85) collate utf8_unicode_ci not null,
40+
number int not null,
41+
name varchar(10) not null,
42+
primary key (key1, key2, key3, key4, key5, key6, key7)
43+
) ENGINE=ndbcluster DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;;
44+
45+
*/
46+
public abstract class DynamicStringPKs extends DynamicObject {
47+
48+
public String getKey1() {
49+
return (String)get(0);
50+
}
51+
public String getKey2() {
52+
return (String)get(1);
53+
}
54+
public String getKey3() {
55+
return (String)get(2);
56+
}
57+
public Integer getKey4() {
58+
return (Integer)get(3);
59+
}
60+
public String getKey5() {
61+
return (String)get(4);
62+
}
63+
public Integer getKey6() {
64+
return (Integer)get(5);
65+
}
66+
public String getKey7() {
67+
return (String)get(6);
68+
}
69+
public void setKey1(String str) {
70+
set(0, str);
71+
}
72+
public void setKey2(String str) {
73+
set(1, str);
74+
}
75+
public void setKey3(String str) {
76+
set(2, str);
77+
}
78+
public void setKey4(int val) {
79+
set(3, val);
80+
}
81+
public void setKey5(String str) {
82+
set(4, str);
83+
}
84+
public void setKey6(int val) {
85+
set(5, val);
86+
}
87+
public void setKey7(String str) {
88+
set(6, str);
89+
}
90+
91+
public int getNumber() {
92+
return (Integer)get(7);
93+
}
94+
public void setNumber(int value) {
95+
set(7, value);
96+
}
97+
98+
public String getName() {
99+
return (String)get(8);
100+
}
101+
public void setName(String value) {
102+
set(8, value);
103+
}
104+
}

storage/ndb/clusterj/clusterj-test/src/main/resources/schema.sql

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights
1+
-- Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights
22
-- reserved.
33
--
44
-- This program is free software; you can redistribute it and/or
@@ -133,6 +133,20 @@ create table varbinarytypes (
133133

134134
) ENGINE=ndbcluster DEFAULT CHARSET=latin1;
135135

136+
drop table if exists dynamicstringpks;
137+
create table dynamicstringpks (
138+
key1 VARCHAR(85) collate utf8_unicode_ci NOT NULL,
139+
key2 VARCHAR(85) collate utf8_unicode_ci NOT NULL,
140+
key3 VARCHAR(85) collate utf8_unicode_ci NOT NULL,
141+
key4 INT NOT NULL,
142+
key5 VARCHAR(85) collate utf8_unicode_ci NOT NULL,
143+
key6 INT NOT NULL,
144+
key7 VARCHAR(85) collate utf8_unicode_ci NOT NULL,
145+
number INT NOT NULL,
146+
name VARCHAR(10) NOT NULL,
147+
PRIMARY KEY (key1, key2, key3, key4, key5, key6, key7)
148+
) ENGINE=ndbcluster DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
149+
136150
drop table if exists binarypk;
137151
create table binarypk (
138152
id binary(255) primary key not null,

0 commit comments

Comments
 (0)