@@ -516,6 +516,23 @@ mysqlnd_stmt_copy_it(zval *** copies, zval * original, unsigned int param_count,
516
516
/* }}} */
517
517
518
518
519
+ /* {{{ mysqlnd_stmt_free_copies */
520
+ static void
521
+ mysqlnd_stmt_free_copies (MYSQLND_STMT_DATA * stmt , zval * * copies TSRMLS_DC )
522
+ {
523
+ if (copies ) {
524
+ unsigned int i ;
525
+ for (i = 0 ; i < stmt -> param_count ; i ++ ) {
526
+ if (copies [i ]) {
527
+ zval_ptr_dtor (& copies [i ]);
528
+ }
529
+ }
530
+ mnd_efree (copies );
531
+ }
532
+ }
533
+ /* }}} */
534
+
535
+
519
536
/* {{{ mysqlnd_stmt_execute_check_n_enlarge_buffer */
520
537
static enum_func_status
521
538
mysqlnd_stmt_execute_check_n_enlarge_buffer (zend_uchar * * buf , zend_uchar * * p , size_t * buf_len , zend_uchar * const provided_buffer , size_t needed_bytes TSRMLS_DC )
@@ -544,51 +561,24 @@ mysqlnd_stmt_execute_check_n_enlarge_buffer(zend_uchar **buf, zend_uchar **p, si
544
561
/* }}} */
545
562
546
563
547
- /* {{{ mysqlnd_stmt_execute_store_params */
564
+ /* {{{ mysqlnd_stmt_execute_prepare_param_types */
548
565
static enum_func_status
549
- mysqlnd_stmt_execute_store_params ( MYSQLND_STMT * s , zend_uchar * * buf , zend_uchar * * p , size_t * buf_len TSRMLS_DC )
566
+ mysqlnd_stmt_execute_prepare_param_types ( MYSQLND_STMT_DATA * stmt , zval * * * copies_param , int * resend_types_next_time TSRMLS_DC )
550
567
{
551
- MYSQLND_STMT_DATA * stmt = s -> data ;
552
- unsigned int i = 0 ;
553
- zend_uchar * provided_buffer = * buf ;
554
- size_t data_size = 0 ;
555
- zval * * copies = NULL ;/* if there are different types */
556
- enum_func_status ret = FAIL ;
557
- int resend_types_next_time = 0 ;
558
- size_t null_byte_offset ;
559
-
560
- DBG_ENTER ("mysqlnd_stmt_execute_store_params" );
561
-
562
- {
563
- unsigned int null_count = (stmt -> param_count + 7 ) / 8 ;
564
- if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer (buf , p , buf_len , provided_buffer , null_count TSRMLS_CC )) {
565
- SET_OOM_ERROR (* stmt -> error_info );
566
- goto end ;
567
- }
568
- /* put `null` bytes */
569
- null_byte_offset = * p - * buf ;
570
- memset (* p , 0 , null_count );
571
- * p += null_count ;
572
- }
573
-
574
- /* 1. Store type information */
575
- /*
576
- check if need to send the types even if stmt->send_types_to_server is 0. This is because
577
- if we send "i" (42) then the type will be int and the server will expect int. However, if next
578
- time we try to send > LONG_MAX, the conversion to string will send a string and the server
579
- won't expect it and interpret the value as 0. Thus we need to resend the types, if any such values
580
- occur, and force resend for the next execution.
581
- */
568
+ unsigned int i ;
569
+ DBG_ENTER ("mysqlnd_stmt_execute_prepare_param_types" );
582
570
for (i = 0 ; i < stmt -> param_count ; i ++ ) {
583
571
short current_type = stmt -> param_bind [i ].type ;
584
572
if (Z_TYPE_P (stmt -> param_bind [i ].zv ) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG )) {
573
+ zval * * copies ;
585
574
/* always copy the var, because we do many conversions */
586
575
if (Z_TYPE_P (stmt -> param_bind [i ].zv ) != IS_LONG &&
587
- PASS != mysqlnd_stmt_copy_it (& copies , stmt -> param_bind [i ].zv , stmt -> param_count , i TSRMLS_CC ))
576
+ PASS != mysqlnd_stmt_copy_it (copies_param , stmt -> param_bind [i ].zv , stmt -> param_count , i TSRMLS_CC ))
588
577
{
589
578
SET_OOM_ERROR (* stmt -> error_info );
590
579
goto end ;
591
580
}
581
+ copies = * copies_param ;
592
582
/*
593
583
if it doesn't fit in a long send it as a string.
594
584
Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX
@@ -613,7 +603,7 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
613
603
We do transformation here, which will be used later when sending types. The code later relies on this.
614
604
*/
615
605
if (Z_DVAL_P (tmp_data_copy ) > LONG_MAX || Z_DVAL_P (tmp_data_copy ) < LONG_MIN ) {
616
- stmt -> send_types_to_server = resend_types_next_time = 1 ;
606
+ stmt -> send_types_to_server = * resend_types_next_time = 1 ;
617
607
convert_to_string_ex (& tmp_data );
618
608
} else {
619
609
convert_to_long_ex (& tmp_data );
@@ -623,54 +613,64 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
623
613
}
624
614
}
625
615
}
616
+ DBG_RETURN (PASS );
617
+ end :
618
+ DBG_RETURN (FAIL );
619
+ }
620
+ /* }}} */
626
621
627
- int1store (* p , stmt -> send_types_to_server );
628
- (* p )++ ;
629
622
630
- if ( stmt -> send_types_to_server ) {
631
- if ( FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer ( buf , p , buf_len , provided_buffer , stmt -> param_count * 2 TSRMLS_CC )) {
632
- SET_OOM_ERROR ( * stmt -> error_info );
633
- goto end ;
634
- }
635
- for (i = 0 ; i < stmt -> param_count ; i ++ ) {
636
- short current_type = stmt -> param_bind [i ].type ;
637
- /* our types are not unsigned */
623
+ /* {{{ mysqlnd_stmt_execute_store_types */
624
+ static void
625
+ mysqlnd_stmt_execute_store_types ( MYSQLND_STMT_DATA * stmt , zval * * copies , zend_uchar * * p )
626
+ {
627
+ unsigned int i ;
628
+ for (i = 0 ; i < stmt -> param_count ; i ++ ) {
629
+ short current_type = stmt -> param_bind [i ].type ;
630
+ /* our types are not unsigned */
638
631
#if SIZEOF_LONG == 8
639
- if (current_type == MYSQL_TYPE_LONG ) {
640
- current_type = MYSQL_TYPE_LONGLONG ;
641
- }
632
+ if (current_type == MYSQL_TYPE_LONG ) {
633
+ current_type = MYSQL_TYPE_LONGLONG ;
634
+ }
642
635
#endif
643
- if (Z_TYPE_P (stmt -> param_bind [i ].zv ) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG )) {
636
+ if (Z_TYPE_P (stmt -> param_bind [i ].zv ) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG )) {
637
+ /*
638
+ if it doesn't fit in a long send it as a string.
639
+ Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX
640
+ */
641
+ if (Z_TYPE_P (stmt -> param_bind [i ].zv ) != IS_LONG ) {
642
+ const zval * tmp_data = (copies && copies [i ])? copies [i ]: stmt -> param_bind [i ].zv ;
644
643
/*
645
- if it doesn't fit in a long send it as a string .
646
- Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX
644
+ In case of IS_LONG we do nothing, it is ok, in case of string, we just need to set current_type .
645
+ The actual transformation has been performed several dozens line above.
647
646
*/
648
- if (Z_TYPE_P (stmt -> param_bind [ i ]. zv ) != IS_LONG ) {
649
- zval * tmp_data = ( copies && copies [ i ])? copies [ i ]: stmt -> param_bind [ i ]. zv ;
647
+ if (Z_TYPE_P (tmp_data ) == IS_STRING ) {
648
+ current_type = MYSQL_TYPE_VAR_STRING ;
650
649
/*
651
- In case of IS_LONG we do nothing, it is ok, in case of string, we just need to set current_type.
652
- The actual transformation has been performed several dozens line above.
650
+ don't change stmt->param_bind[i].type to MYSQL_TYPE_VAR_STRING
651
+ we force convert_to_long_ex in all cases, thus the type will be right in the next switch.
652
+ if the type is however not long, then we will do a goto in the next switch.
653
+ We want to preserve the original bind type given by the user. Thus, we do these hacks.
653
654
*/
654
- if (Z_TYPE_P (tmp_data ) == IS_STRING ) {
655
- current_type = MYSQL_TYPE_VAR_STRING ;
656
- /*
657
- don't change stmt->param_bind[i].type to MYSQL_TYPE_VAR_STRING
658
- we force convert_to_long_ex in all cases, thus the type will be right in the next switch.
659
- if the type is however not long, then we will do a goto in the next switch.
660
- We want to preserve the original bind type given by the user. Thus, we do these hacks.
661
- */
662
- }
663
655
}
664
656
}
665
- int2store (* p , current_type );
666
- * p += 2 ;
667
657
}
658
+ int2store (* p , current_type );
659
+ * p += 2 ;
668
660
}
669
- stmt -> send_types_to_server = resend_types_next_time ;
661
+ }
662
+ /* }}} */
663
+
664
+
665
+ /* {{{ mysqlnd_stmt_execute_calculate_param_values_size */
666
+ static enum_func_status
667
+ mysqlnd_stmt_execute_calculate_param_values_size (MYSQLND_STMT_DATA * stmt , zval * * * copies_param , size_t * data_size TSRMLS_DC )
668
+ {
669
+ unsigned int i ;
670
+ DBG_ENTER ("mysqlnd_stmt_execute_calculate_param_values_size" );
670
671
671
- /* 2. Store data */
672
- /* 2.1 Calculate how much space we need */
673
672
for (i = 0 ; i < stmt -> param_count ; i ++ ) {
673
+ zval * * copies ;
674
674
unsigned int j ;
675
675
zval * the_var = stmt -> param_bind [i ].zv ;
676
676
@@ -681,7 +681,7 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
681
681
if (stmt -> param_bind [j ].zv == the_var ) {
682
682
/* Double binding of the same zval, make a copy */
683
683
if (!copies || !copies [i ]) {
684
- if (PASS != mysqlnd_stmt_copy_it (& copies , the_var , stmt -> param_count , i TSRMLS_CC )) {
684
+ if (PASS != mysqlnd_stmt_copy_it (copies_param , the_var , stmt -> param_count , i TSRMLS_CC )) {
685
685
SET_OOM_ERROR (* stmt -> error_info );
686
686
goto end ;
687
687
}
@@ -690,12 +690,14 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
690
690
}
691
691
}
692
692
693
+ copies = * copies_param ;
694
+
693
695
switch (stmt -> param_bind [i ].type ) {
694
696
case MYSQL_TYPE_DOUBLE :
695
- data_size += 8 ;
697
+ * data_size += 8 ;
696
698
if (Z_TYPE_P (the_var ) != IS_DOUBLE ) {
697
699
if (!copies || !copies [i ]) {
698
- if (PASS != mysqlnd_stmt_copy_it (& copies , the_var , stmt -> param_count , i TSRMLS_CC )) {
700
+ if (PASS != mysqlnd_stmt_copy_it (copies_param , the_var , stmt -> param_count , i TSRMLS_CC )) {
699
701
SET_OOM_ERROR (* stmt -> error_info );
700
702
goto end ;
701
703
}
@@ -710,7 +712,7 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
710
712
}
711
713
convert_to_long_ex (& tmp_data );
712
714
}
713
- data_size += 8 ;
715
+ * data_size += 8 ;
714
716
break ;
715
717
case MYSQL_TYPE_LONG :
716
718
{
@@ -720,7 +722,7 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
720
722
}
721
723
convert_to_long_ex (& tmp_data );
722
724
}
723
- data_size += 4 ;
725
+ * data_size += 4 ;
724
726
break ;
725
727
case MYSQL_TYPE_LONG_BLOB :
726
728
if (!(stmt -> param_bind [i ].flags & MYSQLND_PARAM_BIND_BLOB_USED )) {
@@ -729,35 +731,41 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
729
731
Empty string has length of 0, encoded in 1 byte. No real
730
732
data will follows after it.
731
733
*/
732
- data_size ++ ;
734
+ ( * data_size ) ++ ;
733
735
}
734
736
break ;
735
737
case MYSQL_TYPE_VAR_STRING :
736
738
use_string :
737
- data_size += 8 ; /* max 8 bytes for size */
739
+ * data_size += 8 ; /* max 8 bytes for size */
738
740
if (Z_TYPE_P (the_var ) != IS_STRING ) {
739
741
if (!copies || !copies [i ]) {
740
- if (PASS != mysqlnd_stmt_copy_it (& copies , the_var , stmt -> param_count , i TSRMLS_CC )) {
742
+ if (PASS != mysqlnd_stmt_copy_it (copies_param , the_var , stmt -> param_count , i TSRMLS_CC )) {
741
743
SET_OOM_ERROR (* stmt -> error_info );
742
744
goto end ;
743
745
}
744
746
}
747
+ copies = * copies_param ;
745
748
the_var = copies [i ];
746
749
}
747
750
convert_to_string_ex (& the_var );
748
- data_size += Z_STRLEN_P (the_var );
751
+ * data_size += Z_STRLEN_P (the_var );
749
752
break ;
750
753
}
751
754
}
752
- /* 2.2 Enlarge the buffer, if needed */
753
- if ( FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer ( buf , p , buf_len , provided_buffer , data_size TSRMLS_CC )) {
754
- SET_OOM_ERROR ( * stmt -> error_info );
755
- goto end ;
756
- }
755
+ DBG_RETURN ( PASS );
756
+ end :
757
+ DBG_RETURN ( FAIL );
758
+ }
759
+ /* }}} */
757
760
758
- /* 2.3 Store the actual data */
761
+
762
+ /* {{{ mysqlnd_stmt_execute_store_param_values */
763
+ static void
764
+ mysqlnd_stmt_execute_store_param_values (MYSQLND_STMT_DATA * stmt , zval * * copies , zend_uchar * * buf , zend_uchar * * p , size_t null_byte_offset )
765
+ {
766
+ unsigned int i ;
759
767
for (i = 0 ; i < stmt -> param_count ; i ++ ) {
760
- zval * data = (copies && copies [i ])? copies [i ]: stmt -> param_bind [i ].zv ;
768
+ zval * data = (copies && copies [i ])? copies [i ]: stmt -> param_bind [i ].zv ;
761
769
/* Handle long data */
762
770
if (stmt -> param_bind [i ].zv && Z_TYPE_P (data ) == IS_NULL ) {
763
771
(* buf + null_byte_offset )[i /8 ] |= (zend_uchar ) (1 << (i & 7 ));
@@ -809,17 +817,79 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
809
817
}
810
818
}
811
819
}
812
- ret = PASS ;
813
- end :
814
- if (copies ) {
815
- for (i = 0 ; i < stmt -> param_count ; i ++ ) {
816
- if (copies [i ]) {
817
- zval_ptr_dtor (& copies [i ]);
818
- }
820
+ }
821
+ /* }}} */
822
+
823
+
824
+ /* {{{ mysqlnd_stmt_execute_store_params */
825
+ static enum_func_status
826
+ mysqlnd_stmt_execute_store_params (MYSQLND_STMT * s , zend_uchar * * buf , zend_uchar * * p , size_t * buf_len TSRMLS_DC )
827
+ {
828
+ MYSQLND_STMT_DATA * stmt = s -> data ;
829
+ zend_uchar * provided_buffer = * buf ;
830
+ size_t data_size = 0 ;
831
+ zval * * copies = NULL ;/* if there are different types */
832
+ enum_func_status ret = FAIL ;
833
+ int resend_types_next_time = 0 ;
834
+ size_t null_byte_offset ;
835
+
836
+ DBG_ENTER ("mysqlnd_stmt_execute_store_params" );
837
+
838
+ {
839
+ unsigned int null_count = (stmt -> param_count + 7 ) / 8 ;
840
+ if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer (buf , p , buf_len , provided_buffer , null_count TSRMLS_CC )) {
841
+ SET_OOM_ERROR (* stmt -> error_info );
842
+ goto end ;
819
843
}
820
- mnd_efree (copies );
844
+ /* put `null` bytes */
845
+ null_byte_offset = * p - * buf ;
846
+ memset (* p , 0 , null_count );
847
+ * p += null_count ;
848
+ }
849
+
850
+ /* 1. Store type information */
851
+ /*
852
+ check if need to send the types even if stmt->send_types_to_server is 0. This is because
853
+ if we send "i" (42) then the type will be int and the server will expect int. However, if next
854
+ time we try to send > LONG_MAX, the conversion to string will send a string and the server
855
+ won't expect it and interpret the value as 0. Thus we need to resend the types, if any such values
856
+ occur, and force resend for the next execution.
857
+ */
858
+ if (FAIL == mysqlnd_stmt_execute_prepare_param_types (stmt , & copies , & resend_types_next_time TSRMLS_CC )) {
859
+ goto end ;
860
+ }
861
+
862
+ int1store (* p , stmt -> send_types_to_server );
863
+ (* p )++ ;
864
+
865
+ if (stmt -> send_types_to_server ) {
866
+ if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer (buf , p , buf_len , provided_buffer , stmt -> param_count * 2 TSRMLS_CC )) {
867
+ SET_OOM_ERROR (* stmt -> error_info );
868
+ goto end ;
869
+ }
870
+ mysqlnd_stmt_execute_store_types (stmt , copies , p );
871
+ }
872
+ stmt -> send_types_to_server = resend_types_next_time ;
873
+
874
+ /* 2. Store actual data */
875
+ /* 2.1 Calculate how much space we need */
876
+ if (FAIL == mysqlnd_stmt_execute_calculate_param_values_size (stmt , & copies , & data_size TSRMLS_CC )) {
877
+ goto end ;
878
+ }
879
+
880
+ /* 2.2 Enlarge the buffer, if needed */
881
+ if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer (buf , p , buf_len , provided_buffer , data_size TSRMLS_CC )) {
882
+ SET_OOM_ERROR (* stmt -> error_info );
883
+ goto end ;
821
884
}
822
885
886
+ /* 2.3 Store the actual data */
887
+ mysqlnd_stmt_execute_store_param_values (stmt , copies , buf , p , null_byte_offset );
888
+
889
+ ret = PASS ;
890
+ end :
891
+ mysqlnd_stmt_free_copies (stmt , copies TSRMLS_CC );
892
+
823
893
DBG_INF_FMT ("ret=%s" , ret == PASS ? "PASS" :"FAIL" );
824
894
DBG_RETURN (ret );
825
895
}
@@ -828,7 +898,7 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
828
898
829
899
/* {{{ mysqlnd_stmt_execute_generate_request */
830
900
enum_func_status
831
- mysqlnd_stmt_execute_generate_request (MYSQLND_STMT * const s , zend_uchar * * request , size_t * request_len , zend_bool * free_buffer TSRMLS_DC )
901
+ mysqlnd_stmt_execute_generate_request (MYSQLND_STMT * const s , zend_uchar * * request , size_t * request_len , zend_bool * free_buffer TSRMLS_DC )
832
902
{
833
903
MYSQLND_STMT_DATA * stmt = s -> data ;
834
904
zend_uchar * p = stmt -> execute_cmd_buffer .buffer ,
0 commit comments