Skip to content

Commit 0ec3eea

Browse files
alamarashapkin
andauthored
GG-27261 Python client incorrect hash code calculation for classes as composite keys (#6)
* GG-27261 Python client incorrect hash code calculation for classes as composite keys Co-authored-by: Aleksandr Shapkin <lexwert@yandex.ru>
1 parent 672be9a commit 0ec3eea

5 files changed

Lines changed: 128 additions & 3 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.idea
2+
.vscode
23
.eggs
34
.pytest_cache
45
pygridgain.egg-info

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,5 @@ installed, and GridGain node is running on localhost:10800.
8989
## Testing
9090
Run
9191
```
92-
$ cd gridgain/modules/platforms/python
9392
$ python setup.py pytest
9493
```

pygridgain/binary.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def _build(self, client: 'Client' = None) -> int:
170170
+ len(field_buffer)
171171
)
172172
header.length = header.schema_offset + ctypes.sizeof(schema_class)
173-
header.hash_code = hashcode(field_buffer + bytes(schema))
173+
header.hash_code = hashcode(field_buffer)
174174

175175
# reuse the results
176176
self._buffer = bytes(header) + field_buffer + bytes(schema)

pygridgain/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def hashcode(string: Union[str, bytes]) -> int:
112112
:param string: UTF-8-encoded string identifier of binary buffer,
113113
:return: hash code.
114114
"""
115-
result = 0
115+
result = 1 if isinstance(string, (bytes, bytearray)) else 0
116116
for char in string:
117117
try:
118118
char = ord(char)
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#
2+
# Copyright 2019 GridGain Systems, Inc. and Contributors.
3+
#
4+
# Licensed under the GridGain Community Edition License (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# https://www.gridgain.com/products/software/community-edition/gridgain-community-edition-license
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
from collections import OrderedDict
17+
18+
import pytest
19+
20+
from pygridgain import GenericObjectMeta
21+
from pygridgain.datatypes import (
22+
IntObject, String
23+
)
24+
25+
26+
class StudentKey(
27+
metaclass=GenericObjectMeta,
28+
type_name='test.model.StudentKey',
29+
schema=OrderedDict([
30+
('ID', IntObject),
31+
('DEPT', String)
32+
])
33+
):
34+
pass
35+
36+
37+
class Student(
38+
metaclass=GenericObjectMeta,
39+
type_name='test.model.Student',
40+
schema=OrderedDict([
41+
('NAME', String),
42+
])
43+
):
44+
pass
45+
46+
47+
create_query = '''CREATE TABLE StudentTable (
48+
id INT(11),
49+
dept VARCHAR,
50+
name CHAR(24),
51+
PRIMARY KEY (id, dept))
52+
WITH "CACHE_NAME=StudentCache, KEY_TYPE=test.model.StudentKey, VALUE_TYPE=test.model.Student"'''
53+
54+
insert_query = '''INSERT INTO StudentTable (id, dept, name) VALUES (?, ?, ?)'''
55+
56+
select_query = 'SELECT _KEY, id, dept, name FROM StudentTable'
57+
58+
drop_query = 'DROP TABLE StudentTable IF EXISTS'
59+
60+
61+
def test_cache_get_with_composite_key_finds_sql_value(client):
62+
"""
63+
Should query a record with composite key and calculate
64+
internal hashcode correctly.
65+
"""
66+
67+
client.sql(drop_query)
68+
69+
# Create table.
70+
result = client.sql(create_query)
71+
assert next(result)[0] == 0
72+
73+
student_key = StudentKey(1, 'Acct')
74+
student_val = Student('John')
75+
76+
# Put new Strudent with StudentKey.
77+
result = client.sql(insert_query, query_args=[student_key.ID, student_key.DEPT, student_val.NAME])
78+
assert next(result)[0] == 1
79+
80+
# Cache get finds the same value.
81+
studentCache = client.get_cache('StudentCache')
82+
val = studentCache.get(student_key)
83+
assert val is not None
84+
assert val.NAME == student_val.NAME
85+
86+
query_result = list(client.sql(select_query, include_field_names=True))
87+
88+
validate_query_result(student_key, student_val, query_result)
89+
90+
91+
def test_python_sql_finds_inserted_value_with_composite_key(client):
92+
"""
93+
Insert a record with a composite key and query it with SELECT SQL.
94+
"""
95+
96+
client.sql(drop_query)
97+
98+
# Create table.
99+
result = client.sql(create_query)
100+
assert next(result)[0] == 0
101+
102+
student_key = StudentKey(2, 'Business')
103+
student_val = Student('Abe')
104+
105+
# Put new value using cache.
106+
studentCache = client.get_cache('StudentCache')
107+
studentCache.put(student_key, student_val)
108+
109+
# Find the value using SQL.
110+
query_result = list(client.sql(select_query, include_field_names=True))
111+
112+
validate_query_result(student_key, student_val, query_result)
113+
114+
115+
def validate_query_result(student_key, student_val, query_result):
116+
'''
117+
Compare query result with expected key and value.
118+
'''
119+
assert len(query_result) == 2
120+
sql_row = dict(zip(query_result[0], query_result[1]))
121+
122+
assert sql_row["_KEY"][0] == student_key._buffer
123+
assert sql_row['ID'] == student_key.ID
124+
assert sql_row['DEPT'] == student_key.DEPT
125+
assert sql_row['NAME'] == student_val.NAME

0 commit comments

Comments
 (0)