Skip to content

Commit 6c8e8bc

Browse files
author
Anthony Yeh
committed
php: Fix client for query.proto revamp.
1 parent 956f1c7 commit 6c8e8bc

5 files changed

Lines changed: 144 additions & 107 deletions

File tree

php/src/VTCursor.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function close() {
3131

3232
public function next() {
3333
if ($this->rows && ++ $this->pos < count($this->rows)) {
34-
return $this->rows[$this->pos]->getValuesList();
34+
return VTProto::RowValues($this->rows[$this->pos]);
3535
} else {
3636
return FALSE;
3737
}
@@ -68,14 +68,14 @@ public function close() {
6868
public function next() {
6969
// Get the next row from the current QueryResult.
7070
if ($this->rows && ++ $this->pos < count($this->rows)) {
71-
return $this->rows[$this->pos]->getValuesList();
71+
return VTProto::RowValues($this->rows[$this->pos]);
7272
}
7373

7474
// Get the next QueryResult. Loop in case we get a QueryResult with no rows (e.g. only fields).
7575
while ($this->nextQueryResult()) {
7676
// Get the first row from the new QueryResult.
7777
if ($this->rows && ++ $this->pos < count($this->rows)) {
78-
return $this->rows[$this->pos]->getValuesList();
78+
return VTProto::RowValues($this->rows[$this->pos]);
7979
}
8080
}
8181

php/src/VTProto.php

Lines changed: 99 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,38 @@
1515
* encode as unsigned int.
1616
*
1717
* This is necessary because PHP doesn't have a real unsigned int type.
18+
*
19+
* You can pass in a signed int value, in which case the re-interpreted
20+
* 64-bit 2's complement value will be sent as an unsigned int.
21+
* For example:
22+
* new VTUnsignedInt(42) // will send 42
23+
* new VTUnsignedInt(-1) // will send 0xFFFFFFFFFFFFFFFF
24+
*
25+
* You can also pass in a string consisting of only decimal digits.
26+
* For example:
27+
* new VTUnsignedInt('12345') // will send 12345
1828
*/
1929
class VTUnsignedInt {
20-
public $value;
30+
private $value;
2131

2232
public function __construct($value) {
2333
if (is_int($value)) {
2434
$this->value = $value;
35+
} else if (is_string($value)) {
36+
if (! ctype_digit($value)) {
37+
throw new VTBadInputException('Invalid string value given for VTUnsignedInt: ' . $value);
38+
}
39+
$this->value = $value;
2540
} else {
26-
throw new VTException('Unsupported type for VTUnsignedInt');
41+
throw new VTBadInputException('Unsupported type for VTUnsignedInt');
42+
}
43+
}
44+
45+
public function __toString() {
46+
if (is_int($this->value)) {
47+
return sprintf('%u', $this->value);
48+
} else {
49+
return strval($this->value);
2750
}
2851
}
2952
}
@@ -69,69 +92,62 @@ public static function BoundQuery($query, $vars) {
6992
public static function BindVariable($value) {
7093
$bind_var = new \query\BindVariable();
7194

72-
if (is_null($value)) {
73-
$bind_var->setType(\query\BindVariable\Type::TYPE_NULL);
74-
} else if (is_string($value)) {
75-
$bind_var->setType(\query\BindVariable\Type::TYPE_BYTES);
76-
$bind_var->setValueBytes($value);
77-
} else if (is_int($value)) {
78-
$bind_var->setType(\query\BindVariable\Type::TYPE_INT);
79-
$bind_var->setValueInt($value);
80-
} else if (is_float($value)) {
81-
$bind_var->setType(\query\BindVariable\Type::TYPE_FLOAT);
82-
$bind_var->setValueFloat($value);
83-
} else if (is_object($value)) {
84-
switch (get_class($value)) {
85-
case 'VTUnsignedInt':
86-
$bind_var->setType(\query\BindVariable\Type::TYPE_UINT);
87-
$bind_var->setValueUint($value->value);
88-
break;
89-
default:
90-
throw new VTException('Unknown bind variable class: ' . get_class($value));
95+
if (is_array($value)) {
96+
if (count($value) == 0) {
97+
throw new VTBadInputException('Empty list not allowed for list bind variable');
98+
}
99+
100+
$bind_var->setType(\query\Type::TUPLE);
101+
102+
foreach ($value as $elem) {
103+
list ( $type, $tval ) = self::TypedValue($elem);
104+
$bind_var->addValues((new \query\Value())->setType($type)->setValue($tval));
91105
}
92-
} else if (is_array($value)) {
93-
self::ListBindVariable($bind_var, $value);
94106
} else {
95-
throw new VTException('Unknown bind variable type.');
107+
list ( $type, $tval ) = self::TypedValue($value);
108+
$bind_var->setType($type);
109+
$bind_var->setValue($tval);
96110
}
97111

98112
return $bind_var;
99113
}
100114

101-
protected static function ListBindVariable(&$bind_var, array $list) {
102-
if (count($list) == 0) {
103-
// The list is empty, so it has no type. VTTablet will reject an empty
104-
// list anyway, so we'll just pretend it was a list of bytes.
105-
$bind_var->setType(\query\BindVariable\Type::TYPE_BYTES_LIST);
106-
return;
107-
}
108-
109-
// Check type of first item to determine type of list.
110-
// We only support lists whose elements have uniform types.
111-
if (is_string($list[0])) {
112-
$bind_var->setType(\query\BindVariable\Type::TYPE_BYTES_LIST);
113-
$bind_var->setValueBytesList($list);
114-
} else if (is_int($list[0])) {
115-
$bind_var->setType(\query\BindVariable\Type::TYPE_INT_LIST);
116-
$bind_var->setValueIntList($list);
117-
} else if (is_float($list[0])) {
118-
$bind_var->setType(\query\BindVariable\Type::TYPE_FLOAT_LIST);
119-
$bind_var->setValueFloatList($list);
120-
} else if (is_object($list[0])) {
121-
switch (get_class($list[0])) {
115+
/**
116+
* Returns a tuple of detected \query\Type and string value compatible with \query\Value.
117+
*/
118+
protected static function TypedValue($value) {
119+
if (is_null($value)) {
120+
return array(
121+
\query\Type::NULL_,
122+
''
123+
);
124+
} else if (is_string($value)) {
125+
return array(
126+
\query\Type::VARBINARY,
127+
$value
128+
);
129+
} else if (is_int($value)) {
130+
return array(
131+
\query\Type::INT64,
132+
strval($value)
133+
);
134+
} else if (is_float($value)) {
135+
return array(
136+
\query\Type::FLOAT64,
137+
strval($value)
138+
);
139+
} else if (is_object($value)) {
140+
switch (get_class($value)) {
122141
case 'VTUnsignedInt':
123-
$bind_var->setType(\query\BindVariable\Type::TYPE_UINT_LIST);
124-
$value = array();
125-
foreach ($list as $val) {
126-
$value[] = $val->value;
127-
}
128-
$bind_var->setValueUintList($value);
129-
break;
142+
return array(
143+
\query\Type::UINT64,
144+
strval($value)
145+
);
130146
default:
131-
throw new VTException('Unknown list bind variable class: ' . get_class($list[0]));
147+
throw new VTBadInputException('Unknown \query\Value variable class: ' . get_class($value));
132148
}
133149
} else {
134-
throw new VTException('Unknown list bind variable type.');
150+
throw new VTBadInputException('Unknown type for \query\Value proto:' . gettype($value));
135151
}
136152
}
137153

@@ -162,27 +178,9 @@ public static function EntityId($keyspace_id, $value) {
162178
$eid = new \vtgate\ExecuteEntityIdsRequest\EntityId();
163179
$eid->setKeyspaceId($keyspace_id);
164180

165-
if (is_string($value)) {
166-
$eid->setXidType(\vtgate\ExecuteEntityIdsRequest\EntityId\Type::TYPE_BYTES);
167-
$eid->setXidBytes($value);
168-
} else if (is_int($value)) {
169-
$eid->setXidType(\vtgate\ExecuteEntityIdsRequest\EntityId\Type::TYPE_INT);
170-
$eid->setXidInt($value);
171-
} else if (is_float($value)) {
172-
$eid->setXidType(\vtgate\ExecuteEntityIdsRequest\EntityId\Type::TYPE_FLOAT);
173-
$eid->setXidFloat($value);
174-
} else if (is_object($value)) {
175-
switch (get_class($value)) {
176-
case 'VTUnsignedInt':
177-
$eid->setXidType(\vtgate\ExecuteEntityIdsRequest\EntityId\Type::TYPE_UINT);
178-
$eid->setXidUint($value->value);
179-
break;
180-
default:
181-
throw new VTException('Unknown entity ID class: ' . get_class($value));
182-
}
183-
} else {
184-
throw new VTException('Unknown entity ID type.');
185-
}
181+
list ( $type, $tval ) = self::TypedValue($value);
182+
$eid->setXidType($type);
183+
$eid->setXidValue($tval);
186184

187185
return $eid;
188186
}
@@ -208,5 +206,31 @@ public function BoundKeyspaceIdQuery($query, $bind_vars, $keyspace, $keyspace_id
208206
$value->setKeyspaceIds($keyspace_ids);
209207
return $value;
210208
}
209+
210+
public function RowValues($row) {
211+
$values = array();
212+
213+
// Row values are packed into a single buffer.
214+
// See the docs for the Row message in query.proto.
215+
$start = 0;
216+
$buf = $row->getValues();
217+
$lengths = $row->getLengths();
218+
foreach ($lengths as $len) {
219+
if ($len < 0) {
220+
// This indicates a MySQL NULL value,
221+
// to distinguish it from a zero-length string.
222+
$values[] = NULL;
223+
} else {
224+
$val = substr($buf, $start, $len);
225+
if ($val === FALSE || strlen($val) != $len) {
226+
throw new VTException('Index out of bounds while decoding Row values');
227+
}
228+
$values[] = $val;
229+
$start += $len;
230+
}
231+
}
232+
233+
return $values;
234+
}
211235
}
212236

php/tests/VTGateConnTest.php

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class VTGateConnTest extends PHPUnit_Framework_TestCase {
1919
'unknown error' => 'VTException'
2020
);
2121
private static $BIND_VARS; // initialized in setUpBeforeClass()
22-
private static $BIND_VARS_ECHO = 'map[bytes:[104 101 108 108 111] float:1.5 int:123 uint_from_int:18446744073709551493]'; // 18446744073709551493 = uint64(-123)
22+
private static $BIND_VARS_ECHO = 'map[bytes:[104 101 108 108 111] float:1.5 int:123 uint_from_int:18446744073709551493 uint_from_string:456]'; // 18446744073709551493 = uint64(-123)
2323
private static $CALLER_ID; // initialized in setUpBeforeClass()
2424
private static $CALLER_ID_ECHO = 'principal:"test_principal" component:"test_component" subcomponent:"test_subcomponent" ';
2525
private static $TABLET_TYPE = \topodata\TabletType::REPLICA;
@@ -37,7 +37,7 @@ class VTGateConnTest extends PHPUnit_Framework_TestCase {
3737
private static $KEY_RANGES_ECHO = '[end:"\200\000\000\000\000\000\000\000" start:"\200\000\000\000\000\000\000\000" ]';
3838
private static $ENTITY_COLUMN_NAME = 'test_column';
3939
private static $ENTITY_KEYSPACE_IDS; // initialized in setUpBeforeClass()
40-
private static $ENTITY_KEYSPACE_IDS_ECHO = '[xid_type:TYPE_FLOAT xid_float:1.5 keyspace_id:"\0224Vx\000\000\000\002" xid_type:TYPE_INT xid_int:123 keyspace_id:"\0224Vx\000\000\000\000" xid_type:TYPE_UINT xid_uint:456 keyspace_id:"\0224Vx\000\000\000\001" ]';
40+
private static $ENTITY_KEYSPACE_IDS_ECHO = '[xid_type:FLOAT64 xid_value:"1.5" keyspace_id:"\0224Vx\000\000\000\002" xid_type:INT64 xid_value:"123" keyspace_id:"\0224Vx\000\000\000\000" xid_type:UINT64 xid_value:"456" keyspace_id:"\0224Vx\000\000\000\001" ]';
4141
private static $SESSION_ECHO = 'InTransaction: true, ShardSession: []';
4242

4343
public static function setUpBeforeClass() {
@@ -82,6 +82,7 @@ public static function setUpBeforeClass() {
8282
'bytes' => 'hello',
8383
'int' => 123,
8484
'uint_from_int' => new VTUnsignedInt(- 123),
85+
'uint_from_string' => new VTUnsignedInt('456'),
8586
'float' => 1.5
8687
);
8788
self::$CALLER_ID = new \vtrpc\CallerID();
@@ -333,17 +334,12 @@ public function testEchoSplitQuery() {
333334
'bytes' => 'hello',
334335
'float' => 1.5,
335336
'int' => 123,
336-
'uint_from_int' => new VTUnsignedInt(345)
337-
);
338-
$expected_bind_vars = array(
339-
'bytes' => 'hello',
340-
'float' => 1.5,
341-
'int' => 123,
342-
'uint_from_int' => new VTUnsignedInt(345)
337+
'uint_from_int' => new VTUnsignedInt(345),
338+
'uint_from_string' => new VTUnsignedInt('678')
343339
);
344340

345341
$expected = new \vtgate\SplitQueryResponse\Part();
346-
$expected->setQuery(VTProto::BoundQuery(self::$ECHO_QUERY . ':split_column:123', $expected_bind_vars));
342+
$expected->setQuery(VTProto::BoundQuery(self::$ECHO_QUERY . ':split_column:123', $input_bind_vars));
347343
$krpart = new \vtgate\SplitQueryResponse\KeyRangePart();
348344
$krpart->setKeyspace(self::$KEYSPACE);
349345
$expected->setKeyRangePart($krpart);

php/tests/VTProtoTest.php

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,34 @@ class VTProtoTest extends PHPUnit_Framework_TestCase {
77
public function testBoundQuery() {
88
$expected = new \query\BoundQuery();
99
$expected->setSql('test query');
10-
add_bind_var($expected, \query\BindVariable\Type::TYPE_BYTES, 'setValueBytes', 'bytes', 'hello');
11-
add_bind_var($expected, \query\BindVariable\Type::TYPE_INT, 'setValueInt', 'int', 123);
12-
add_bind_var($expected, \query\BindVariable\Type::TYPE_UINT, 'setValueUint', 'uint_from_int', - 123);
13-
add_bind_var($expected, \query\BindVariable\Type::TYPE_FLOAT, 'setValueFloat', 'float', 1.5);
14-
add_bind_var($expected, \query\BindVariable\Type::TYPE_BYTES_LIST, 'setValueBytesList', 'bytes_list', array(
10+
add_bind_var($expected, \query\Type::VARBINARY, 'bytes', 'hello');
11+
add_bind_var($expected, \query\Type::INT64, 'int', '123');
12+
add_bind_var($expected, \query\Type::UINT64, 'uint_from_int', '18446744073709551493'); // 18446744073709551493 = uint64(-123)
13+
add_bind_var($expected, \query\Type::UINT64, 'uint_from_string', '456');
14+
add_bind_var($expected, \query\Type::FLOAT64, 'float', '1.5');
15+
add_list_bind_var($expected, \query\Type::VARBINARY, 'bytes_list', array(
1516
'one',
1617
'two'
1718
));
18-
add_bind_var($expected, \query\BindVariable\Type::TYPE_INT_LIST, 'setValueIntList', 'int_list', array(
19-
1,
20-
2,
21-
3
19+
add_list_bind_var($expected, \query\Type::INT64, 'int_list', array(
20+
'1',
21+
'2',
22+
'3'
2223
));
23-
add_bind_var($expected, \query\BindVariable\Type::TYPE_UINT_LIST, 'setValueUintList', 'uint_list', array(
24-
123,
25-
456
24+
add_list_bind_var($expected, \query\Type::UINT64, 'uint_list', array(
25+
'123',
26+
'456'
2627
));
27-
add_bind_var($expected, \query\BindVariable\Type::TYPE_FLOAT_LIST, 'setValueFloatList', 'float_list', array(
28-
2.0,
29-
4.0
28+
add_list_bind_var($expected, \query\Type::FLOAT64, 'float_list', array(
29+
'2.0',
30+
'4.0'
3031
));
3132

3233
$actual = VTProto::BoundQuery('test query', array(
3334
'bytes' => 'hello',
3435
'int' => 123,
3536
'uint_from_int' => new VTUnsignedInt(- 123),
37+
'uint_from_string' => new VTUnsignedInt('456'),
3638
'float' => 1.5,
3739
'bytes_list' => array(
3840
'one',
@@ -45,7 +47,7 @@ public function testBoundQuery() {
4547
),
4648
'uint_list' => array(
4749
new VTUnsignedInt(123),
48-
new VTUnsignedInt(456)
50+
new VTUnsignedInt('456')
4951
),
5052
'float_list' => array(
5153
2.0,

php/tests/VTTestUtils.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,26 @@
11
<?php
22

3-
function add_bind_var($bound_query, $type, $method, $key, $value) {
3+
function add_bind_var($bound_query, $type, $key, $value) {
44
$bv = new \query\BindVariable();
55
$bv->setType($type);
6-
$bv->$method($value);
6+
$bv->setValue($value);
77
$entry = new \query\BoundQuery\BindVariablesEntry();
88
$entry->setKey($key);
99
$entry->setValue($bv);
1010
$bound_query->addBindVariables($entry);
11-
}
11+
}
12+
13+
function add_list_bind_var($bound_query, $type, $key, $values) {
14+
$bv = new \query\BindVariable();
15+
$bv->setType(\query\Type::TUPLE);
16+
foreach ($values as $value) {
17+
$val = new \query\Value();
18+
$val->setType($type);
19+
$val->setValue($value);
20+
$bv->addValues($val);
21+
}
22+
$entry = new \query\BoundQuery\BindVariablesEntry();
23+
$entry->setKey($key);
24+
$entry->setValue($bv);
25+
$bound_query->addBindVariables($entry);
26+
}

0 commit comments

Comments
 (0)