@@ -348,7 +348,10 @@ static int validate_ascii(const char* data, int length) {
348
348
}
349
349
350
350
/* TODO our platform better be little-endian w/ 4-byte ints! */
351
- /* returns 0 on failure */
351
+ /* Write a single value to the buffer (also write it's type_byte, for which
352
+ * space has already been reserved.
353
+ *
354
+ * returns 0 on failure */
352
355
static int write_element_to_buffer (bson_buffer * buffer , int type_byte , PyObject * value , unsigned char check_keys ) {
353
356
/* TODO this isn't quite the same as the Python version:
354
357
* here we check for type equivalence, not isinstance in some
@@ -771,13 +774,23 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject*
771
774
DBRef = PyObject_GetAttrString (module , "DBRef" );
772
775
Py_DECREF (module );
773
776
777
+ module = PyImport_ImportModule ("uuid" );
778
+ if (!module ) {
779
+ UUID = NULL ;
780
+ PyErr_Clear ();
781
+ } else {
782
+ UUID = PyObject_GetAttrString (module , "UUID" );
783
+ Py_DECREF (module );
784
+ }
785
+
774
786
if (PyObject_IsInstance (value , Binary ) ||
775
787
PyObject_IsInstance (value , Code ) ||
776
788
PyObject_IsInstance (value , ObjectId ) ||
777
- PyObject_IsInstance (value , DBRef )) {
789
+ PyObject_IsInstance (value , DBRef ) ||
790
+ (UUID && PyObject_IsInstance (value , UUID ))) {
778
791
779
792
PyErr_SetString (PyExc_RuntimeError ,
780
- "A pymongo module was reloaded without the C extension being reloaded.\n"
793
+ "A python module was reloaded without the C extension being reloaded.\n"
781
794
"\n"
782
795
"See http://www.mongodb.org/display/DOCS/PyMongo+and+mod_wsgi for"
783
796
"a possible explanation / fix." );
@@ -794,25 +807,51 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject*
794
807
}
795
808
}
796
809
797
- static int check_key_name (const unsigned char check_keys ,
798
- const char * name ,
810
+ static int check_key_name (const char * name ,
799
811
const Py_ssize_t name_length ) {
800
- if (check_keys ) {
801
- int i ;
802
- if (name_length > 0 && name [0 ] == '$' ) {
803
- PyObject * errmsg = PyString_FromFormat ("key '%s' must not start with '$'" , name );
812
+ int i ;
813
+ if (name_length > 0 && name [0 ] == '$' ) {
814
+ PyObject * errmsg = PyString_FromFormat ("key '%s' must not start with '$'" , name );
815
+ PyErr_SetString (InvalidName , PyString_AsString (errmsg ));
816
+ Py_DECREF (errmsg );
817
+ return 0 ;
818
+ }
819
+ for (i = 0 ; i < name_length ; i ++ ) {
820
+ if (name [i ] == '.' ) {
821
+ PyObject * errmsg = PyString_FromFormat ("key '%s' must not contain '.'" , name );
804
822
PyErr_SetString (InvalidName , PyString_AsString (errmsg ));
805
823
Py_DECREF (errmsg );
806
824
return 0 ;
807
825
}
808
- for (i = 0 ; i < name_length ; i ++ ) {
809
- if (name [i ] == '.' ) {
810
- PyObject * errmsg = PyString_FromFormat ("key '%s' must not contain '.'" , name );
811
- PyErr_SetString (InvalidName , PyString_AsString (errmsg ));
812
- Py_DECREF (errmsg );
813
- return 0 ;
814
- }
815
- }
826
+ }
827
+ return 1 ;
828
+ }
829
+
830
+ /* Write a (key, value) pair to the buffer.
831
+ *
832
+ * Returns 0 on failure */
833
+ static int write_pair (bson_buffer * buffer , const char * name , Py_ssize_t name_length , PyObject * value , unsigned char check_keys , unsigned char allow_id ) {
834
+ int type_byte ;
835
+
836
+ /* Don't write any _id elements unless we're explicitly told to -
837
+ * _id has to be written first so we write do so, but don't bother
838
+ * deleting it from the dictionary being written. */
839
+ if (!allow_id && strcmp (name , "_id" ) == 0 ) {
840
+ return 1 ;
841
+ }
842
+
843
+ type_byte = buffer_save_bytes (buffer , 1 );
844
+ if (type_byte == -1 ) {
845
+ return 0 ;
846
+ }
847
+ if (check_keys && !check_key_name (name , name_length )) {
848
+ return 0 ;
849
+ }
850
+ if (!buffer_write_bytes (buffer , name , name_length + 1 )) {
851
+ return 0 ;
852
+ }
853
+ if (!write_element_to_buffer (buffer , type_byte , value , check_keys )) {
854
+ return 0 ;
816
855
}
817
856
return 1 ;
818
857
}
@@ -830,8 +869,6 @@ static int write_son(bson_buffer* buffer, PyObject* dict, int start_position,
830
869
PyObject * key ;
831
870
PyObject * value ;
832
871
PyObject * encoded ;
833
- int type_byte ;
834
- Py_ssize_t name_length ;
835
872
836
873
key = PyList_GetItem (keys , i );
837
874
if (!key ) {
@@ -843,11 +880,6 @@ static int write_son(bson_buffer* buffer, PyObject* dict, int start_position,
843
880
Py_DECREF (keys );
844
881
return 0 ;
845
882
}
846
- type_byte = buffer_save_bytes (buffer , 1 );
847
- if (type_byte == -1 ) {
848
- Py_DECREF (keys );
849
- return 0 ;
850
- }
851
883
if (PyUnicode_CheckExact (key )) {
852
884
encoded = PyUnicode_AsUTF8String (key );
853
885
if (!encoded ) {
@@ -858,28 +890,11 @@ static int write_son(bson_buffer* buffer, PyObject* dict, int start_position,
858
890
encoded = key ;
859
891
Py_INCREF (encoded );
860
892
}
861
- name_length = PyString_Size (encoded );
862
- {
863
- const char * name = PyString_AsString (encoded );
864
- if (!name ) {
865
- Py_DECREF (keys );
866
- Py_DECREF (encoded );
867
- return 0 ;
868
- }
869
- if (!check_key_name (check_keys , name , name_length )) {
870
- Py_DECREF (keys );
871
- Py_DECREF (encoded );
872
- return 0 ;
873
- }
874
- if (!buffer_write_bytes (buffer , name , name_length + 1 )) {
875
- Py_DECREF (keys );
876
- Py_DECREF (encoded );
877
- return 0 ;
878
- }
879
- }
880
- Py_DECREF (encoded );
881
- if (!write_element_to_buffer (buffer , type_byte , value , check_keys )) {
893
+ /* Don't allow writing _id here - it was written above. */
894
+ if (!write_pair (buffer , PyString_AsString (encoded ),
895
+ PyString_Size (encoded ), value , check_keys , 0 )) {
882
896
Py_DECREF (keys );
897
+ Py_DECREF (encoded );
883
898
return 0 ;
884
899
}
885
900
}
@@ -893,28 +908,37 @@ static int write_dict(bson_buffer* buffer, PyObject* dict, unsigned char check_k
893
908
char zero = 0 ;
894
909
int length ;
895
910
911
+ int is_dict = PyDict_Check (dict );
912
+
896
913
/* save space for length */
897
914
int length_location = buffer_save_bytes (buffer , 4 );
898
915
if (length_location == -1 ) {
899
916
return 0 ;
900
917
}
901
918
919
+ /* Write _id first if we have one, whether or not we're SON. */
920
+ if (is_dict ) {
921
+ PyObject * _id = PyDict_GetItemString (dict , "_id" );
922
+ if (_id ) {
923
+ /* Don't bother checking keys, but do make sure we're allowed to
924
+ * write _id */
925
+ if (!write_pair (buffer , "_id" , 3 , _id , 0 , 1 )) {
926
+ return 0 ;
927
+ }
928
+ }
929
+ }
930
+
902
931
if (PyObject_IsInstance (dict , SON )) {
903
932
if (!write_son (buffer , dict , start_position , length_location , check_keys )) {
904
933
return 0 ;
905
934
}
906
- } else if (PyDict_Check ( dict ) ) {
935
+ } else if (is_dict ) {
907
936
PyObject * key ;
908
937
PyObject * value ;
909
938
Py_ssize_t pos = 0 ;
939
+
910
940
while (PyDict_Next (dict , & pos , & key , & value )) {
911
941
PyObject * encoded ;
912
- Py_ssize_t name_length ;
913
-
914
- int type_byte = buffer_save_bytes (buffer , 1 );
915
- if (type_byte == -1 ) {
916
- return 0 ;
917
- }
918
942
if (PyUnicode_CheckExact (key )) {
919
943
encoded = PyUnicode_AsUTF8String (key );
920
944
if (!encoded ) {
@@ -924,51 +948,20 @@ static int write_dict(bson_buffer* buffer, PyObject* dict, unsigned char check_k
924
948
encoded = key ;
925
949
Py_INCREF (encoded );
926
950
}
927
- name_length = PyString_Size (encoded );
928
- {
929
- const char * name = PyString_AsString (encoded );
930
- if (!name ) {
931
- Py_DECREF (encoded );
932
- return 0 ;
933
- }
934
- if (!check_key_name (check_keys , name , name_length )) {
935
- Py_DECREF (encoded );
936
- return 0 ;
937
- }
938
- if (!buffer_write_bytes (buffer , name , name_length + 1 )) {
939
- Py_DECREF (encoded );
940
- return 0 ;
941
- }
942
- }
943
- Py_DECREF (encoded );
944
- if (!write_element_to_buffer (buffer , type_byte , value , check_keys )) {
951
+ /* Don't allow writing _id here - it was written above. */
952
+ if (!write_pair (buffer , PyString_AsString (encoded ),
953
+ PyString_Size (encoded ), value , check_keys , 0 )) {
954
+ Py_DECREF (encoded );
945
955
return 0 ;
946
956
}
947
957
}
948
958
} else {
949
- /* Try getting the SON class again
950
- * This can be necessary if pymongo.son has been reloaded, since
951
- * reloading the module breaks IsInstance.
952
- * The main reason we even try this is to raise an informative exception
953
- * about it. */
954
- PyObject * son_module = PyImport_ImportModule ("pymongo.son" );
955
- SON = PyObject_GetAttrString (son_module , "SON" );
956
- Py_DECREF (son_module );
957
- if (PyObject_IsInstance (dict , SON )) {
958
- PyErr_SetString (PyExc_RuntimeError ,
959
- "pymongo.son was reloaded without the C extension being reloaded.\n"
960
- "\n"
961
- "See http://www.mongodb.org/display/DOCS/PyMongo+and+mod_wsgi for"
962
- "a possible explanation / fix." );
963
- return 0 ;
964
- } else {
965
- PyObject * errmsg = PyString_FromString ("encoder expected a mapping type but got: " );
966
- PyObject * repr = PyObject_Repr (dict );
967
- PyString_ConcatAndDel (& errmsg , repr );
968
- PyErr_SetString (PyExc_TypeError , PyString_AsString (errmsg ));
969
- Py_DECREF (errmsg );
970
- return 0 ;
971
- }
959
+ PyObject * errmsg = PyString_FromString ("encoder expected a mapping type but got: " );
960
+ PyObject * repr = PyObject_Repr (dict );
961
+ PyString_ConcatAndDel (& errmsg , repr );
962
+ PyErr_SetString (PyExc_TypeError , PyString_AsString (errmsg ));
963
+ Py_DECREF (errmsg );
964
+ return 0 ;
972
965
}
973
966
974
967
/* write null byte and fill in length */
0 commit comments