@@ -22,13 +22,13 @@ cdef class CoreProtocol:
22
22
self .xact_status = PQTRANS_IDLE
23
23
self .encoding = ' utf-8'
24
24
25
- # executemany support data
26
- self ._execute_iter = None
27
- self ._execute_portal_name = None
28
- self ._execute_stmt_name = None
29
-
30
25
self ._reset_result()
31
26
27
+ cpdef is_in_transaction(self ):
28
+ # PQTRANS_INTRANS = idle, within transaction block
29
+ # PQTRANS_INERROR = idle, within failed transaction
30
+ return self .xact_status in (PQTRANS_INTRANS, PQTRANS_INERROR)
31
+
32
32
cdef _read_server_messages(self ):
33
33
cdef:
34
34
char mtype
@@ -253,22 +253,7 @@ cdef class CoreProtocol:
253
253
elif mtype == b' Z' :
254
254
# ReadyForQuery
255
255
self ._parse_msg_ready_for_query()
256
- if self .result_type == RESULT_FAILED:
257
- self ._push_result()
258
- else :
259
- try :
260
- buf = < WriteBuffer> next(self ._execute_iter)
261
- except StopIteration :
262
- self ._push_result()
263
- except Exception as e:
264
- self .result_type = RESULT_FAILED
265
- self .result = e
266
- self ._push_result()
267
- else :
268
- # Next iteration over the executemany() arg sequence
269
- self ._send_bind_message(
270
- self ._execute_portal_name, self ._execute_stmt_name,
271
- buf, 0 )
256
+ self ._push_result()
272
257
273
258
elif mtype == b' I' :
274
259
# EmptyQueryResponse
@@ -687,6 +672,17 @@ cdef class CoreProtocol:
687
672
if self .con_status != CONNECTION_OK:
688
673
raise apg_exc.InternalClientError(' not connected' )
689
674
675
+ cdef WriteBuffer _build_parse_message(self , str stmt_name, str query):
676
+ cdef WriteBuffer buf
677
+
678
+ buf = WriteBuffer.new_message(b' P' )
679
+ buf.write_str(stmt_name, self .encoding)
680
+ buf.write_str(query, self .encoding)
681
+ buf.write_int16(0 )
682
+
683
+ buf.end_message()
684
+ return buf
685
+
690
686
cdef WriteBuffer _build_bind_message(self , str portal_name,
691
687
str stmt_name,
692
688
WriteBuffer bind_data):
@@ -702,6 +698,25 @@ cdef class CoreProtocol:
702
698
buf.end_message()
703
699
return buf
704
700
701
+ cdef WriteBuffer _build_empty_bind_data(self ):
702
+ cdef WriteBuffer buf
703
+ buf = WriteBuffer.new()
704
+ buf.write_int16(0 ) # The number of parameter format codes
705
+ buf.write_int16(0 ) # The number of parameter values
706
+ buf.write_int16(0 ) # The number of result-column format codes
707
+ return buf
708
+
709
+ cdef WriteBuffer _build_execute_message(self , str portal_name,
710
+ int32_t limit):
711
+ cdef WriteBuffer buf
712
+
713
+ buf = WriteBuffer.new_message(b' E' )
714
+ buf.write_str(portal_name, self .encoding) # name of the portal
715
+ buf.write_int32(limit) # number of rows to return; 0 - all
716
+
717
+ buf.end_message()
718
+ return buf
719
+
705
720
# API for subclasses
706
721
707
722
cdef _connect(self ):
@@ -752,12 +767,7 @@ cdef class CoreProtocol:
752
767
self ._ensure_connected()
753
768
self ._set_state(PROTOCOL_PREPARE)
754
769
755
- buf = WriteBuffer.new_message(b' P' )
756
- buf.write_str(stmt_name, self .encoding)
757
- buf.write_str(query, self .encoding)
758
- buf.write_int16(0 )
759
- buf.end_message()
760
- packet = buf
770
+ packet = self ._build_parse_message(stmt_name, query)
761
771
762
772
buf = WriteBuffer.new_message(b' D' )
763
773
buf.write_byte(b' S' )
@@ -779,10 +789,7 @@ cdef class CoreProtocol:
779
789
buf = self ._build_bind_message(portal_name, stmt_name, bind_data)
780
790
packet = buf
781
791
782
- buf = WriteBuffer.new_message(b' E' )
783
- buf.write_str(portal_name, self .encoding) # name of the portal
784
- buf.write_int32(limit) # number of rows to return; 0 - all
785
- buf.end_message()
792
+ buf = self ._build_execute_message(portal_name, limit)
786
793
packet.write_buffer(buf)
787
794
788
795
packet.write_bytes(SYNC_MESSAGE)
@@ -801,30 +808,75 @@ cdef class CoreProtocol:
801
808
802
809
self ._send_bind_message(portal_name, stmt_name, bind_data, limit)
803
810
804
- cdef _bind_execute_many(self , str portal_name, str stmt_name,
805
- object bind_data):
806
-
807
- cdef WriteBuffer buf
808
-
811
+ cdef _execute_many_init(self ):
809
812
self ._ensure_connected()
810
813
self ._set_state(PROTOCOL_BIND_EXECUTE_MANY)
811
814
812
815
self .result = None
813
816
self ._discard_data = True
814
- self ._execute_iter = bind_data
815
- self ._execute_portal_name = portal_name
816
- self ._execute_stmt_name = stmt_name
817
817
818
- try :
819
- buf = < WriteBuffer> next(bind_data)
820
- except StopIteration :
821
- self ._push_result()
822
- except Exception as e:
823
- self .result_type = RESULT_FAILED
824
- self .result = e
818
+ cdef _execute_many_writelines(self , str portal_name, str stmt_name,
819
+ object bind_data):
820
+ cdef:
821
+ WriteBuffer packet
822
+ WriteBuffer buf
823
+ list buffers = []
824
+
825
+ if self .result_type == RESULT_FAILED:
826
+ raise StopIteration (True )
827
+
828
+ while len (buffers) < _EXECUTE_MANY_BUF_NUM:
829
+ packet = WriteBuffer.new()
830
+
831
+ while packet.len() < _EXECUTE_MANY_BUF_SIZE:
832
+ try :
833
+ buf = < WriteBuffer> next(bind_data)
834
+ except StopIteration :
835
+ if packet.len() > 0 :
836
+ buffers.append(packet)
837
+ if len (buffers) > 0 :
838
+ self ._writelines(buffers)
839
+ raise StopIteration (True )
840
+ else :
841
+ raise StopIteration (False )
842
+ except Exception as ex:
843
+ raise StopIteration (ex)
844
+ packet.write_buffer(
845
+ self ._build_bind_message(portal_name, stmt_name, buf))
846
+ packet.write_buffer(
847
+ self ._build_execute_message(portal_name, 0 ))
848
+ buffers.append(packet)
849
+ self ._writelines(buffers)
850
+
851
+ cdef _execute_many_done(self , bint data_sent):
852
+ if data_sent:
853
+ self ._write(SYNC_MESSAGE)
854
+ else :
825
855
self ._push_result()
856
+
857
+ cdef _execute_many_fail(self , object error):
858
+ cdef WriteBuffer buf
859
+
860
+ self .result_type = RESULT_FAILED
861
+ self .result = error
862
+
863
+ # We shall rollback in an implicit transaction to prevent partial
864
+ # commit, while do nothing in an explicit transaction and leaving the
865
+ # error to the user
866
+ if self .is_in_transaction():
867
+ self ._execute_many_done(True )
826
868
else :
827
- self ._send_bind_message(portal_name, stmt_name, buf, 0 )
869
+ # Here if the implicit transaction is in `ignore_till_sync` mode,
870
+ # the `ROLLBACK` will be ignored and `Sync` will restore the state;
871
+ # or else the implicit transaction will be rolled back with a
872
+ # warning saying that there was no transaction, but rollback is
873
+ # done anyway, so we could ignore this warning.
874
+ buf = self ._build_parse_message(' ' , ' ROLLBACK' )
875
+ buf.write_buffer(self ._build_bind_message(
876
+ ' ' , ' ' , self ._build_empty_bind_data()))
877
+ buf.write_buffer(self ._build_execute_message(' ' , 0 ))
878
+ buf.write_bytes(SYNC_MESSAGE)
879
+ self ._write(buf)
828
880
829
881
cdef _execute(self , str portal_name, int32_t limit):
830
882
cdef WriteBuffer buf
@@ -834,10 +886,7 @@ cdef class CoreProtocol:
834
886
835
887
self .result = []
836
888
837
- buf = WriteBuffer.new_message(b' E' )
838
- buf.write_str(portal_name, self .encoding) # name of the portal
839
- buf.write_int32(limit) # number of rows to return; 0 - all
840
- buf.end_message()
889
+ buf = self ._build_execute_message(portal_name, limit)
841
890
842
891
buf.write_bytes(SYNC_MESSAGE)
843
892
@@ -920,6 +969,9 @@ cdef class CoreProtocol:
920
969
cdef _write(self , buf):
921
970
raise NotImplementedError
922
971
972
+ cdef _writelines(self , list buffers):
973
+ raise NotImplementedError
974
+
923
975
cdef _decode_row(self , const char * buf, ssize_t buf_len):
924
976
pass
925
977
0 commit comments