00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <Python.h>
00024
00025 #include "_cbson.h"
00026 #include "buffer.h"
00027
00028
00029
00030
00031 static PyObject* _error(char* name) {
00032 PyObject* error;
00033 PyObject* errors = PyImport_ImportModule("pymongo.errors");
00034 if (!errors) {
00035 return NULL;
00036 }
00037 error = PyObject_GetAttrString(errors, name);
00038 Py_DECREF(errors);
00039 return error;
00040 }
00041
00042
00043
00044 static int add_last_error(buffer_t buffer, int request_id, PyObject* args) {
00045 int message_start;
00046 int document_start;
00047 int message_length;
00048 int document_length;
00049 PyObject* key;
00050 PyObject* value;
00051 Py_ssize_t pos = 0;
00052 PyObject* one;
00053
00054 message_start = buffer_save_space(buffer, 4);
00055 if (message_start == -1) {
00056 PyErr_NoMemory();
00057 return 0;
00058 }
00059 if (!buffer_write_bytes(buffer, (const char*)&request_id, 4) ||
00060 !buffer_write_bytes(buffer,
00061 "\x00\x00\x00\x00"
00062 "\xd4\x07\x00\x00"
00063 "\x00\x00\x00\x00"
00064 "admin.$cmd\x00"
00065 "\x00\x00\x00\x00"
00066 "\xFF\xFF\xFF\xFF",
00067 31)) {
00068 return 0;
00069 }
00070
00071
00072 document_start = buffer_save_space(buffer, 4);
00073 if (document_start == -1) {
00074 PyErr_NoMemory();
00075 return 0;
00076 }
00077
00078
00079 one = PyLong_FromLong(1);
00080 if (!write_pair(buffer, "getlasterror", 12, one, 0, 1)) {
00081 Py_DECREF(one);
00082 return 0;
00083 }
00084 Py_DECREF(one);
00085
00086
00087 while (PyDict_Next(args, &pos, &key, &value)) {
00088 if (!decode_and_write_pair(buffer, key, value, 0, 0)) {
00089 return 0;
00090 }
00091 }
00092
00093
00094 if (!buffer_write_bytes(buffer, "\x00", 1)) {
00095 return 0;
00096 }
00097
00098 message_length = buffer_get_position(buffer) - message_start;
00099 document_length = buffer_get_position(buffer) - document_start;
00100 memcpy(buffer_get_buffer(buffer) + message_start, &message_length, 4);
00101 memcpy(buffer_get_buffer(buffer) + document_start, &document_length, 4);
00102 return 1;
00103 }
00104
00105 static PyObject* _cbson_insert_message(PyObject* self, PyObject* args) {
00106
00107 int request_id = rand();
00108 char* collection_name = NULL;
00109 int collection_name_length;
00110 PyObject* docs;
00111 int before, cur_size, max_size = 0;
00112 int list_length;
00113 int i;
00114 unsigned char check_keys;
00115 unsigned char safe;
00116 PyObject* last_error_args;
00117 buffer_t buffer;
00118 int length_location;
00119 PyObject* result;
00120
00121 if (!PyArg_ParseTuple(args, "et#ObbO",
00122 "utf-8",
00123 &collection_name,
00124 &collection_name_length,
00125 &docs, &check_keys, &safe, &last_error_args)) {
00126 return NULL;
00127 }
00128
00129 buffer = buffer_new();
00130 if (!buffer) {
00131 PyErr_NoMemory();
00132 PyMem_Free(collection_name);
00133 return NULL;
00134 }
00135
00136
00137 length_location = buffer_save_space(buffer, 4);
00138 if (length_location == -1) {
00139 PyMem_Free(collection_name);
00140 PyErr_NoMemory();
00141 return NULL;
00142 }
00143 if (!buffer_write_bytes(buffer, (const char*)&request_id, 4) ||
00144 !buffer_write_bytes(buffer,
00145 "\x00\x00\x00\x00"
00146 "\xd2\x07\x00\x00"
00147 "\x00\x00\x00\x00",
00148 12) ||
00149 !buffer_write_bytes(buffer,
00150 collection_name,
00151 collection_name_length + 1)) {
00152 PyMem_Free(collection_name);
00153 buffer_free(buffer);
00154 return NULL;
00155 }
00156
00157 PyMem_Free(collection_name);
00158
00159 list_length = PyList_Size(docs);
00160 if (list_length <= 0) {
00161 PyObject* InvalidOperation = _error("InvalidOperation");
00162 PyErr_SetString(InvalidOperation, "cannot do an empty bulk insert");
00163 Py_DECREF(InvalidOperation);
00164 buffer_free(buffer);
00165 return NULL;
00166 }
00167 for (i = 0; i < list_length; i++) {
00168 PyObject* doc = PyList_GetItem(docs, i);
00169 before = buffer_get_position(buffer);
00170 if (!write_dict(buffer, doc, check_keys, 1)) {
00171 buffer_free(buffer);
00172 return NULL;
00173 }
00174 cur_size = buffer_get_position(buffer) - before;
00175 max_size = (cur_size > max_size) ? cur_size : max_size;
00176 }
00177
00178 memcpy(buffer_get_buffer(buffer) + length_location,
00179 buffer_get_buffer(buffer) + buffer_get_position(buffer), 4);
00180
00181 if (safe) {
00182 if (!add_last_error(buffer, request_id, last_error_args)) {
00183 buffer_free(buffer);
00184 return NULL;
00185 }
00186 }
00187
00188
00189 result = Py_BuildValue("is#i", request_id,
00190 buffer_get_buffer(buffer),
00191 buffer_get_position(buffer),
00192 max_size);
00193 buffer_free(buffer);
00194 return result;
00195 }
00196
00197 static PyObject* _cbson_update_message(PyObject* self, PyObject* args) {
00198
00199 int request_id = rand();
00200 char* collection_name = NULL;
00201 int collection_name_length;
00202 int before, cur_size, max_size = 0;
00203 PyObject* doc;
00204 PyObject* spec;
00205 unsigned char multi;
00206 unsigned char upsert;
00207 unsigned char safe;
00208 PyObject* last_error_args;
00209 int options;
00210 buffer_t buffer;
00211 int length_location;
00212 PyObject* result;
00213
00214 if (!PyArg_ParseTuple(args, "et#bbOObO",
00215 "utf-8",
00216 &collection_name,
00217 &collection_name_length,
00218 &upsert, &multi, &spec, &doc, &safe,
00219 &last_error_args)) {
00220 return NULL;
00221 }
00222
00223 options = 0;
00224 if (upsert) {
00225 options += 1;
00226 }
00227 if (multi) {
00228 options += 2;
00229 }
00230 buffer = buffer_new();
00231 if (!buffer) {
00232 PyErr_NoMemory();
00233 PyMem_Free(collection_name);
00234 return NULL;
00235 }
00236
00237
00238 length_location = buffer_save_space(buffer, 4);
00239 if (length_location == -1) {
00240 PyMem_Free(collection_name);
00241 PyErr_NoMemory();
00242 return NULL;
00243 }
00244 if (!buffer_write_bytes(buffer, (const char*)&request_id, 4) ||
00245 !buffer_write_bytes(buffer,
00246 "\x00\x00\x00\x00"
00247 "\xd1\x07\x00\x00"
00248 "\x00\x00\x00\x00",
00249 12) ||
00250 !buffer_write_bytes(buffer,
00251 collection_name,
00252 collection_name_length + 1) ||
00253 !buffer_write_bytes(buffer, (const char*)&options, 4)) {
00254 buffer_free(buffer);
00255 PyMem_Free(collection_name);
00256 return NULL;
00257 }
00258
00259 before = buffer_get_position(buffer);
00260 if (!write_dict(buffer, spec, 0, 1)) {
00261 buffer_free(buffer);
00262 PyMem_Free(collection_name);
00263 return NULL;
00264 }
00265 max_size = buffer_get_position(buffer) - before;
00266
00267 before = buffer_get_position(buffer);
00268 if (!write_dict(buffer, doc, 0, 1)) {
00269 buffer_free(buffer);
00270 PyMem_Free(collection_name);
00271 return NULL;
00272 }
00273 cur_size = buffer_get_position(buffer) - before;
00274 max_size = (cur_size > max_size) ? cur_size : max_size;
00275
00276 PyMem_Free(collection_name);
00277
00278 memcpy(buffer_get_buffer(buffer) + length_location,
00279 buffer_get_buffer(buffer) + buffer_get_position(buffer), 4);
00280
00281 if (safe) {
00282 if (!add_last_error(buffer, request_id, last_error_args)) {
00283 buffer_free(buffer);
00284 return NULL;
00285 }
00286 }
00287
00288
00289 result = Py_BuildValue("is#i", request_id,
00290 buffer_get_buffer(buffer),
00291 buffer_get_position(buffer),
00292 max_size);
00293 buffer_free(buffer);
00294 return result;
00295 }
00296
00297 static PyObject* _cbson_query_message(PyObject* self, PyObject* args) {
00298
00299 int request_id = rand();
00300 unsigned int options;
00301 char* collection_name = NULL;
00302 int collection_name_length;
00303 int begin, cur_size, max_size = 0;
00304 int num_to_skip;
00305 int num_to_return;
00306 PyObject* query;
00307 PyObject* field_selector = Py_None;
00308 buffer_t buffer;
00309 int length_location;
00310 PyObject* result;
00311
00312 if (!PyArg_ParseTuple(args, "Iet#iiO|O",
00313 &options,
00314 "utf-8",
00315 &collection_name,
00316 &collection_name_length,
00317 &num_to_skip, &num_to_return,
00318 &query, &field_selector)) {
00319 return NULL;
00320 }
00321 buffer = buffer_new();
00322 if (!buffer) {
00323 PyErr_NoMemory();
00324 PyMem_Free(collection_name);
00325 return NULL;
00326 }
00327
00328
00329 length_location = buffer_save_space(buffer, 4);
00330 if (length_location == -1) {
00331 PyMem_Free(collection_name);
00332 PyErr_NoMemory();
00333 return NULL;
00334 }
00335 if (!buffer_write_bytes(buffer, (const char*)&request_id, 4) ||
00336 !buffer_write_bytes(buffer, "\x00\x00\x00\x00\xd4\x07\x00\x00", 8) ||
00337 !buffer_write_bytes(buffer, (const char*)&options, 4) ||
00338 !buffer_write_bytes(buffer, collection_name,
00339 collection_name_length + 1) ||
00340 !buffer_write_bytes(buffer, (const char*)&num_to_skip, 4) ||
00341 !buffer_write_bytes(buffer, (const char*)&num_to_return, 4)) {
00342 buffer_free(buffer);
00343 PyMem_Free(collection_name);
00344 return NULL;
00345 }
00346
00347 begin = buffer_get_position(buffer);
00348 if (!write_dict(buffer, query, 0, 1)) {
00349 buffer_free(buffer);
00350 PyMem_Free(collection_name);
00351 return NULL;
00352 }
00353 max_size = buffer_get_position(buffer) - begin;
00354
00355 if (field_selector != Py_None) {
00356 begin = buffer_get_position(buffer);
00357 if (!write_dict(buffer, field_selector, 0, 1)) {
00358 buffer_free(buffer);
00359 PyMem_Free(collection_name);
00360 return NULL;
00361 }
00362 cur_size = buffer_get_position(buffer) - begin;
00363 max_size = (cur_size > max_size) ? cur_size : max_size;
00364 }
00365
00366 PyMem_Free(collection_name);
00367
00368 memcpy(buffer_get_buffer(buffer) + length_location,
00369 buffer_get_buffer(buffer) + buffer_get_position(buffer), 4);
00370
00371
00372 result = Py_BuildValue("is#i", request_id,
00373 buffer_get_buffer(buffer),
00374 buffer_get_position(buffer),
00375 max_size);
00376 buffer_free(buffer);
00377 return result;
00378 }
00379
00380 static PyObject* _cbson_get_more_message(PyObject* self, PyObject* args) {
00381
00382 int request_id = rand();
00383 char* collection_name = NULL;
00384 int collection_name_length;
00385 int num_to_return;
00386 long long cursor_id;
00387 buffer_t buffer;
00388 int length_location;
00389 PyObject* result;
00390
00391 if (!PyArg_ParseTuple(args, "et#iL",
00392 "utf-8",
00393 &collection_name,
00394 &collection_name_length,
00395 &num_to_return,
00396 &cursor_id)) {
00397 return NULL;
00398 }
00399 buffer = buffer_new();
00400 if (!buffer) {
00401 PyErr_NoMemory();
00402 PyMem_Free(collection_name);
00403 return NULL;
00404 }
00405
00406
00407 length_location = buffer_save_space(buffer, 4);
00408 if (length_location == -1) {
00409 PyMem_Free(collection_name);
00410 PyErr_NoMemory();
00411 return NULL;
00412 }
00413 if (!buffer_write_bytes(buffer, (const char*)&request_id, 4) ||
00414 !buffer_write_bytes(buffer,
00415 "\x00\x00\x00\x00"
00416 "\xd5\x07\x00\x00"
00417 "\x00\x00\x00\x00", 12) ||
00418 !buffer_write_bytes(buffer,
00419 collection_name,
00420 collection_name_length + 1) ||
00421 !buffer_write_bytes(buffer, (const char*)&num_to_return, 4) ||
00422 !buffer_write_bytes(buffer, (const char*)&cursor_id, 8)) {
00423 buffer_free(buffer);
00424 PyMem_Free(collection_name);
00425 return NULL;
00426 }
00427
00428 PyMem_Free(collection_name);
00429
00430 memcpy(buffer_get_buffer(buffer) + length_location,
00431 buffer_get_buffer(buffer) + buffer_get_position(buffer), 4);
00432
00433
00434 result = Py_BuildValue("is#", request_id,
00435 buffer_get_buffer(buffer),
00436 buffer_get_position(buffer));
00437 buffer_free(buffer);
00438 return result;
00439 }
00440
00441 static PyMethodDef _CMessageMethods[] = {
00442 {"_insert_message", _cbson_insert_message, METH_VARARGS,
00443 "create an insert message to be sent to MongoDB"},
00444 {"_update_message", _cbson_update_message, METH_VARARGS,
00445 "create an update message to be sent to MongoDB"},
00446 {"_query_message", _cbson_query_message, METH_VARARGS,
00447 "create a query message to be sent to MongoDB"},
00448 {"_get_more_message", _cbson_get_more_message, METH_VARARGS,
00449 "create a get more message to be sent to MongoDB"},
00450 {NULL, NULL, 0, NULL}
00451 };
00452
00453 PyMODINIT_FUNC init_cmessage(void) {
00454 PyObject *m;
00455
00456
00457
00458
00459
00460
00461 m = PyImport_ImportModule("bson._cbson");
00462 Py_DECREF(m);
00463
00464 m = Py_InitModule("_cmessage", _CMessageMethods);
00465 if (m == NULL) {
00466 return;
00467 }
00468 }