3131#include "php_pdo_pgsql.h"
3232#include "php_pdo_pgsql_int.h"
3333#include "zend_exceptions.h"
34+ #include "zend_interfaces.h"
3435#include "zend_smart_str.h"
3536#include "pgsql_driver_arginfo.h"
3637
@@ -606,6 +607,32 @@ static bool pgsql_handle_rollback(pdo_dbh_t *dbh)
606607 return ret ;
607608}
608609
610+ static bool _pdo_pgsql_send_copy_data (pdo_pgsql_db_handle * H , zval * line ) {
611+ size_t query_len ;
612+ char * query ;
613+
614+ if (!try_convert_to_string (line )) {
615+ return false;
616+ }
617+
618+ query_len = Z_STRLEN_P (line );
619+ query = emalloc (query_len + 2 ); /* room for \n\0 */
620+ memcpy (query , Z_STRVAL_P (line ), query_len );
621+
622+ if (query [query_len - 1 ] != '\n' ) {
623+ query [query_len ++ ] = '\n' ;
624+ }
625+ query [query_len ] = '\0' ;
626+
627+ if (PQputCopyData (H -> server , query , query_len ) != 1 ) {
628+ efree (query );
629+ return false;
630+ }
631+
632+ efree (query );
633+ return true;
634+ }
635+
609636void pgsqlCopyFromArray_internal (INTERNAL_FUNCTION_PARAMETERS )
610637{
611638 pdo_dbh_t * dbh ;
@@ -620,14 +647,14 @@ void pgsqlCopyFromArray_internal(INTERNAL_FUNCTION_PARAMETERS)
620647 PGresult * pgsql_result ;
621648 ExecStatusType status ;
622649
623- if (zend_parse_parameters (ZEND_NUM_ARGS (), "sa |sss!" ,
650+ if (zend_parse_parameters (ZEND_NUM_ARGS (), "sA |sss!" ,
624651 & table_name , & table_name_len , & pg_rows ,
625652 & pg_delim , & pg_delim_len , & pg_null_as , & pg_null_as_len , & pg_fields , & pg_fields_len ) == FAILURE ) {
626653 RETURN_THROWS ();
627654 }
628655
629- if (! zend_hash_num_elements ( Z_ARRVAL_P (pg_rows ))) {
630- zend_argument_must_not_be_empty_error ( 2 );
656+ if (( Z_TYPE_P ( pg_rows ) != IS_ARRAY && ! instanceof_function ( Z_OBJCE_P (pg_rows ), zend_ce_traversable ))) {
657+ zend_argument_type_error ( 2 , "must be of type array or Traversable" );
631658 RETURN_THROWS ();
632659 }
633660
@@ -661,36 +688,35 @@ void pgsqlCopyFromArray_internal(INTERNAL_FUNCTION_PARAMETERS)
661688
662689 if (status == PGRES_COPY_IN && pgsql_result ) {
663690 int command_failed = 0 ;
664- size_t buffer_len = 0 ;
665691 zval * tmp ;
692+ zend_object_iterator * iter ;
666693
667694 PQclear (pgsql_result );
668- ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P (pg_rows ), tmp ) {
669- size_t query_len ;
670- if (!try_convert_to_string (tmp )) {
671- efree (query );
695+
696+ if (Z_TYPE_P (pg_rows ) == IS_ARRAY ) {
697+ ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P (pg_rows ), tmp ) {
698+ if (!_pdo_pgsql_send_copy_data (H , tmp )) {
699+ pdo_pgsql_error (dbh , PGRES_FATAL_ERROR , NULL );
700+ PDO_HANDLE_DBH_ERR ();
701+ RETURN_FALSE ;
702+ }
703+ } ZEND_HASH_FOREACH_END ();
704+ } else {
705+ iter = Z_OBJ_P (pg_rows )-> ce -> get_iterator (Z_OBJCE_P (pg_rows ), pg_rows , 0 );
706+ if (iter == NULL || EG (exception )) {
672707 RETURN_THROWS ();
673708 }
674709
675- if (buffer_len < Z_STRLEN_P (tmp )) {
676- buffer_len = Z_STRLEN_P (tmp );
677- query = erealloc (query , buffer_len + 2 ); /* room for \n\0 */
678- }
679- query_len = Z_STRLEN_P (tmp );
680- memcpy (query , Z_STRVAL_P (tmp ), query_len );
681- if (query [query_len - 1 ] != '\n' ) {
682- query [query_len ++ ] = '\n' ;
683- }
684- query [query_len ] = '\0' ;
685- if (PQputCopyData (H -> server , query , query_len ) != 1 ) {
686- efree (query );
687- pdo_pgsql_error (dbh , PGRES_FATAL_ERROR , NULL );
688- PDO_HANDLE_DBH_ERR ();
689- RETURN_FALSE ;
710+ for (; iter -> funcs -> valid (iter ) == SUCCESS && EG (exception ) == NULL ; iter -> funcs -> move_forward (iter )) {
711+ tmp = iter -> funcs -> get_current_data (iter );
712+ if (!_pdo_pgsql_send_copy_data (H , tmp )) {
713+ zend_iterator_dtor (iter );
714+ pdo_pgsql_error (dbh , PGRES_FATAL_ERROR , NULL );
715+ PDO_HANDLE_DBH_ERR ();
716+ RETURN_FALSE ;
717+ }
690718 }
691- } ZEND_HASH_FOREACH_END ();
692- if (query ) {
693- efree (query );
719+ zend_iterator_dtor (iter );
694720 }
695721
696722 if (PQputCopyEnd (H -> server , NULL ) != 1 ) {
0 commit comments