Skip to content

Commit 65f634c

Browse files
author
James William Pye
committed
Factor element3 and typio into separate .c files.
1 parent fa9f690 commit 65f634c

4 files changed

Lines changed: 351 additions & 322 deletions

File tree

postgresql/protocol/optimized/buffer.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
*
88
* PQ messages normally take the form {type, (size), data}
99
*/
10+
#define include_buffer_types \
11+
mTYPE(pq_message_stream)
12+
1013
struct p_list
1114
{
1215
PyObject *data; /* PyString pushed onto the buffer */
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* copyright 2009, James William Pye
3+
* http://python.projects.postgresql.org
4+
*
5+
*//*
6+
* element3 optimizations.
7+
*/
8+
#define include_element3_functions \
9+
mFUNC(parse_tuple_message, METH_VARARGS, "parse the given tuple data into a tuple of raw data") \
10+
11+
static PyObject *
12+
parse_tuple_message(PyObject *self, PyObject *args)
13+
{
14+
PyObject *rob;
15+
PyObject *ob;
16+
PyObject *typ;
17+
const char *data;
18+
Py_ssize_t dlen = 0;
19+
uint16_t cnatt = 0, natts = 0;
20+
uint32_t attsize = 0;
21+
uint32_t position = 0;
22+
23+
if (!PyArg_ParseTuple(args, "Oy#", &typ, &data, &dlen))
24+
return(NULL);
25+
26+
/*
27+
* Validate that the given "typ" is in fact a PyTuple_Type subtype.
28+
*/
29+
if (typ != Py_None)
30+
{
31+
if (!PyObject_IsSubclass(typ, (PyObject *) &PyTuple_Type))
32+
{
33+
const char *typname = "<not-a-type>";
34+
if (PyObject_IsInstance(
35+
(PyObject *) typ->ob_type,
36+
(PyObject *) &PyType_Type
37+
))
38+
{
39+
typname = ((PyTypeObject *) typ)->tp_name;
40+
}
41+
42+
PyErr_Format(
43+
PyExc_TypeError,
44+
"cannot instantiate wire tuple into a non-tuple subtype: %s",
45+
typname
46+
);
47+
return(NULL);
48+
}
49+
}
50+
else
51+
{
52+
typ = (PyObject *) &PyTuple_Type;
53+
}
54+
55+
if (dlen < 2)
56+
{
57+
PyErr_Format(PyExc_ValueError,
58+
"invalid tuple message: %d bytes is too small", dlen);
59+
return(NULL);
60+
}
61+
natts = ntohs(*((uint16_t *) (data)));
62+
63+
/*
64+
* FEARME: A bit much for saving a reallocation/copy?
65+
*
66+
* This is expected to be used as a classmethod on a tuple subtype that
67+
* has *no* additional attributes.
68+
*
69+
* If the subtype has a custom __new__ routine, this could
70+
* be problematic, but it *should* only lead to AttributeErrors.
71+
*/
72+
rob = ((PyTypeObject *) typ)->tp_alloc((PyTypeObject *) typ, natts);
73+
if (rob == NULL)
74+
{
75+
return(NULL);
76+
}
77+
78+
position += 2;
79+
while (cnatt < natts)
80+
{
81+
/*
82+
* Need enough data for the attribute size.
83+
*/
84+
if (position + 4 > dlen)
85+
{
86+
PyErr_Format(PyExc_ValueError,
87+
"not enough data available for attribute %d's size header: "
88+
"needed %d bytes, but only %lu remain at position %lu",
89+
cnatt, 4, dlen - position, position
90+
);
91+
goto cleanup;
92+
}
93+
94+
attsize = ntohl(*((uint32_t *) (data + position)));
95+
position += 4;
96+
/*
97+
* NULL.
98+
*/
99+
if (attsize == 0xFFFFFFFFL)
100+
{
101+
Py_INCREF(Py_None);
102+
PyTuple_SET_ITEM(rob, cnatt, Py_None);
103+
}
104+
else
105+
{
106+
if ((position + attsize) < position)
107+
{
108+
/*
109+
* Likely a "limitation" over the pure-Python version, *but*
110+
* the message content size is limited to 0xFFFFFFFF-4 anyways,
111+
* so it is unexpected for an attsize to cause wrap-around.
112+
*/
113+
PyErr_Format(PyExc_ValueError,
114+
"tuple data caused position (uint32_t) "
115+
"to wrap on attribute %d, position %lu + size %lu",
116+
cnatt, position, attsize
117+
);
118+
goto cleanup;
119+
}
120+
121+
if (position + attsize > dlen)
122+
{
123+
PyErr_Format(PyExc_ValueError,
124+
"not enough data for attribute %d, size %lu, "
125+
"as only %lu bytes remain in message",
126+
cnatt, attsize, dlen - position
127+
);
128+
goto cleanup;
129+
}
130+
131+
ob = PyBytes_FromStringAndSize(data + position, attsize);
132+
if (ob == NULL)
133+
{
134+
/*
135+
* Probably an OOM error.
136+
*/
137+
goto cleanup;
138+
}
139+
PyTuple_SET_ITEM(rob, cnatt, ob);
140+
position += attsize;
141+
}
142+
143+
cnatt++;
144+
}
145+
146+
if (position != dlen)
147+
{
148+
PyErr_Format(PyExc_ValueError,
149+
"invalid tuple message, %lu remaining "
150+
"bytes after processing %d attributes",
151+
dlen - position, cnatt
152+
);
153+
goto cleanup;
154+
}
155+
156+
return(rob);
157+
158+
cleanup:
159+
Py_DECREF(rob);
160+
return(NULL);
161+
}

0 commit comments

Comments
 (0)