Skip to content

Commit 05e5ea2

Browse files
author
James William Pye
committed
Split the dimensions and lowerbounds into their own tuples.
Also, use divmod() for mktimetuple64...
1 parent db682a6 commit 05e5ea2

4 files changed

Lines changed: 53 additions & 43 deletions

File tree

postgresql/protocol/element3.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,10 +451,14 @@ def serialize(self):
451451
return ushort_pack(len(self)) + pack_tuple_data(self)
452452

453453
@classmethod
454-
def parse(typ, data, T = tuple, ulong_unpack = ulong_unpack):
454+
def parse(typ, data,
455+
T = tuple, ulong_unpack = ulong_unpack,
456+
len = len
457+
):
455458
natts = ushort_unpack(data[0:2])
456459
atts = []
457460
offset = 2
461+
add = atts.append
458462

459463
while natts > 0:
460464
alo = offset
@@ -467,7 +471,7 @@ def parse(typ, data, T = tuple, ulong_unpack = ulong_unpack):
467471
ao = offset
468472
offset = ao + al
469473
att = data[ao:offset]
470-
atts.append(att)
474+
add(att)
471475
natts -= 1
472476
return T(atts)
473477
try:

postgresql/test/test_types.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,11 @@
119119
],
120120

121121
('array', typlib.array_pack, typlib.array_unpack) : [
122-
([0, 0xf, (1, 0), (b'foo',)],
122+
([0, 0xf, (1,), (0,), (b'foo',)],
123123
b'\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x01' \
124124
b'\x00\x00\x00\x00\x00\x00\x00\x03foo'
125125
),
126-
([0, 0xf, (1, 0), (None,)],
126+
([0, 0xf, (1,), (0,), (None,)],
127127
b'\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x01' \
128128
b'\x00\x00\x00\x00\xff\xff\xff\xff'
129129
)
@@ -172,17 +172,17 @@
172172
],
173173

174174
('array', typlib.array_pack, typlib.array_unpack) : [
175-
[0, 0xf, (), ()],
176-
[0, 0xf, (0, 0), ()],
177-
[0, 0xf, (1, 0), (b'foo',)],
178-
[0, 0xf, (1, 0), (None,)],
179-
[0, 0xf, (2, 0), (None,None)],
180-
[0, 0xf, (2, 0), (b'foo',None)],
181-
[0, 0xff, (2, 0), (None,b'foo',)],
182-
[0, 0xffffffff, (3, 0), (None,b'foo',None)],
183-
[1, 0xffffffff, (3, 0), (None,b'foo',None)],
184-
[1, 0xffffffff, (3, 0, 1, 0), (None,b'foo',None)],
185-
[1, 0xffffffff, (3, 0, 2, 0), (None,b'one',b'foo',b'two',None,b'three')],
175+
[0, 0xf, (), (), ()],
176+
[0, 0xf, (0,), (0,), ()],
177+
[0, 0xf, (1,), (0,), (b'foo',)],
178+
[0, 0xf, (1,), (0,), (None,)],
179+
[0, 0xf, (2,), (0,), (None,None)],
180+
[0, 0xf, (2,), (0,), (b'foo',None)],
181+
[0, 0xff, (2,), (0,), (None,b'foo',)],
182+
[0, 0xffffffff, (3,), (0,), (None,b'foo',None)],
183+
[1, 0xffffffff, (3,), (0,), (None,b'foo',None)],
184+
[1, 0xffffffff, (3, 1), (0, 0), (None,b'foo',None)],
185+
[1, 0xffffffff, (3, 2), (0, 0), (None,b'one',b'foo',b'two',None,b'three')],
186186
],
187187

188188
# Just some random data; it's just an integer, so nothing fancy.

postgresql/types/io/lib.py

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import struct
22
from math import floor
33
from ...python.functools import Composition as compose
4+
from ...python.itertools import interlace
45
from ...python.structlib import \
56
short_pack, short_unpack, \
67
ulong_pack, ulong_unpack, \
@@ -77,10 +78,9 @@ def mktimetuple(ts, floor = floor):
7778
seconds = floor(ts)
7879
return (int(seconds), int(1000000 * (ts - seconds)))
7980

80-
def mktimetuple64(ts):
81+
def mktimetuple64(ts, divmod = divmod):
8182
'make a pair of (seconds, microseconds) out of the given long'
82-
seconds = ts // 1000000
83-
return (seconds, ts - (seconds * 1000000))
83+
return divmod(ts, 1000000)
8484

8585
def mktime(seconds_ms, float = float):
8686
'make a double out of the pair of (seconds, microseconds)'
@@ -354,30 +354,35 @@ def elements_pack(elements,
354354
yield long_pack(len(x))
355355
yield x
356356

357-
def array_pack(array_data, llL_pack = llL_pack, len = len, long_pack = long_pack):
357+
def array_pack(array_data,
358+
llL_pack = llL_pack,
359+
len = len,
360+
long_pack = long_pack,
361+
interlace = interlace
362+
):
358363
"""
359364
Pack a raw array. A raw array consists of flags, type oid, sequence of lower
360365
and upper bounds, and an iterable of already serialized element data:
361366
362367
(0, element type oid, (lower bounds, upper bounds, ...), iterable of element_data)
363-
368+
364369
The lower bounds and upper bounds specifies boundaries of the dimension. So the length
365370
of the boundaries sequence is two times the number of dimensions that the array has.
366371
367-
array_pack((flags, type_id, lower_upper_bounds, element_data))
372+
array_pack((flags, type_id, dims, lowers, element_data))
368373
369374
The format of ``lower_upper_bounds`` is a sequence of lower bounds and upper
370375
bounds. First lower then upper inlined within the sequence:
371376
372377
[lower, upper, lower, upper]
373-
378+
374379
The above array `dlb` has two dimensions. The lower and upper bounds of the
375380
first dimension is defined by the first two elements in the sequence. The
376381
second dimension is then defined by the last two elements in the sequence.
377382
"""
378-
(flags, typid, dlb, elements) = array_data
379-
return llL_pack((len(dlb) // 2, flags, typid)) + \
380-
b''.join(map(long_pack, dlb)) + \
383+
(flags, typid, dims, lbs, elements) = array_data
384+
return llL_pack((len(dims), flags, typid)) + \
385+
b''.join(map(long_pack, interlace(dims, lbs))) + \
381386
b''.join(elements_pack(elements))
382387

383388
def elements_unpack(data, offset,
@@ -399,17 +404,23 @@ def elements_unpack(data, offset,
399404
yield data[offset:offset+sizeof_el]
400405
offset += sizeof_el
401406

402-
def array_unpack(data, llL_unpack = llL_unpack, unpack = struct.unpack_from):
407+
def array_unpack(data,
408+
llL_unpack = llL_unpack,
409+
unpack = struct.unpack_from,
410+
long_unpack = long_unpack
411+
):
403412
"""
404413
Given a serialized array, unpack it into a tuple:
405414
406-
(flags, typid, (lower bounds, upper bounds, ...), [elements])
415+
(flags, typid, (dims, lower bounds, ...), [elements])
407416
"""
408417
ndim, flags, typid = llL_unpack(data)
409418
if ndim < 0:
410419
raise ValueError("invalid number of dimensions: %d" %(ndim,))
411420
# "ndim" number of pairs of longs
412421
end = (4 * 2 * ndim) + 12
413-
# Dimension Bounds
414-
dlb = unpack("!%dl"%(2 * ndim,), data, 12)
415-
return (flags, typid, dlb, elements_unpack(data, end))
422+
# Dimensions and lower bounds; split the two early.
423+
#dlb = unpack("!%dl"%(2 * ndim,), data, 12)
424+
dims = [long_unpack(data[x:x+4]) for x in range(12, end, 8)]
425+
lbs = [long_unpack(data[x:x+4]) for x in range(16, end, 8)]
426+
return (flags, typid, dims, lbs, elements_unpack(data, end))

postgresql/types/io/pg_container.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,28 @@
55
from .. import Row, Array, ANYARRAYOID, RECORDOID
66
from ... import exceptions as pg_exc
77
from ...python.functools import process_tuple
8-
from ...python.itertools import interlace
98
from operator import itemgetter
109

1110
##
1211
# array_io_factory - build I/O pair for ARRAYs
1312
##
1413
def array_io_factory(
1514
pack_element, unpack_element,
16-
typoid, hasbin_input, hasbin_output,
15+
typoid, # array element id
16+
hasbin_input, hasbin_output,
1717
array_pack = lib.array_pack,
1818
array_unpack = lib.array_unpack,
1919
ArrayType = Array,
20-
interlace = interlace
2120
):
21+
packed_typoid = lib.ulong_pack(typoid)
2222
if hasbin_input:
2323
def pack_an_array(data):
2424
if not data.__class__ is ArrayType:
2525
# Assume the data is a nested list.
2626
data = ArrayType(data)
2727
return array_pack((
2828
0, # unused flags
29-
typoid, tuple(interlace(data.dimensions, data.lowerbounds)),
29+
typoid, data.dimensions, data.lowerbounds,
3030
(x if x is None else pack_element(x) for x in data.elements()),
3131
))
3232
else:
@@ -35,16 +35,11 @@ def pack_an_array(data):
3535

3636
if hasbin_output:
3737
def unpack_an_array(data):
38-
flags, typoid, dlb, elements = array_unpack(data)
39-
upper = []
40-
lower = []
41-
for x in range(0, len(dlb), 2):
42-
lb = dlb[x+1]
43-
lower.append(lb)
44-
upper.append(dlb[x] + lb - 1)
38+
flags, typoid, dims, lbs, elements = array_unpack(data)
4539
return Array.from_elements(
46-
(x if x is None else unpack_element(x) for x in elements),
47-
lowerbounds = lower, upperbounds = upper,
40+
map(unpack_element, elements),
41+
lowerbounds = lbs,
42+
upperbounds = [x + lb - 1 for x, lb in zip(dims, lbs)]
4843
)
4944
else:
5045
# signals string formatting

0 commit comments

Comments
 (0)