|
29 | 29 | #include "ext/standard/info.h"
|
30 | 30 | #include "pdo/php_pdo.h"
|
31 | 31 | #include "pdo/php_pdo_driver.h"
|
| 32 | +#include "ext/standard/file.h" |
32 | 33 |
|
33 | 34 | #undef PACKAGE_BUGREPORT
|
34 | 35 | #undef PACKAGE_NAME
|
@@ -496,6 +497,368 @@ static int pgsql_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
|
496 | 497 | return pdo_pgsql_transaction_cmd("ROLLBACK", dbh TSRMLS_CC);
|
497 | 498 | }
|
498 | 499 |
|
| 500 | +/* {{{ proto string PDO::pgsqlCopyFromArray(string $table_name , array $rows [, string $delimiter [, string $null_as ] [, string $fields]) |
| 501 | + Returns true if the copy worked fine or false if error */ |
| 502 | +static PHP_METHOD(PDO, pgsqlCopyFromArray) |
| 503 | +{ |
| 504 | + pdo_dbh_t *dbh; |
| 505 | + pdo_pgsql_db_handle *H; |
| 506 | + |
| 507 | + zval *pg_rows; |
| 508 | + |
| 509 | + char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL; |
| 510 | + int table_name_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len; |
| 511 | + char *query; |
| 512 | + |
| 513 | + PGresult *pgsql_result; |
| 514 | + ExecStatusType status; |
| 515 | + |
| 516 | + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s/a|sss", |
| 517 | + &table_name, &table_name_len, &pg_rows, |
| 518 | + &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) { |
| 519 | + return; |
| 520 | + } |
| 521 | + |
| 522 | + if (!zend_hash_num_elements(Z_ARRVAL_P(pg_rows))) { |
| 523 | + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot copy from an empty array"); |
| 524 | + RETURN_FALSE; |
| 525 | + } |
| 526 | + |
| 527 | + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
| 528 | + PDO_CONSTRUCT_CHECK; |
| 529 | + |
| 530 | + if (pg_fields) { |
| 531 | + spprintf(&query, 0, "COPY %s (%s) FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); |
| 532 | + } else { |
| 533 | + spprintf(&query, 0, "COPY %s FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); |
| 534 | + } |
| 535 | + |
| 536 | + // Obtain db Handle |
| 537 | + H = (pdo_pgsql_db_handle *)dbh->driver_data; |
| 538 | + |
| 539 | + while ((pgsql_result = PQgetResult(H->server))) { |
| 540 | + PQclear(pgsql_result); |
| 541 | + } |
| 542 | + pgsql_result = PQexec(H->server, query); |
| 543 | + |
| 544 | + efree(query); |
| 545 | + query = NULL; |
| 546 | + |
| 547 | + if (pgsql_result) { |
| 548 | + status = PQresultStatus(pgsql_result); |
| 549 | + } else { |
| 550 | + status = (ExecStatusType) PQstatus(H->server); |
| 551 | + } |
| 552 | + |
| 553 | + if (status == PGRES_COPY_IN && pgsql_result) { |
| 554 | + int command_failed = 0; |
| 555 | + int buffer_len = 0; |
| 556 | + zval **tmp; |
| 557 | + HashPosition pos; |
| 558 | + |
| 559 | + PQclear(pgsql_result); |
| 560 | + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(pg_rows), &pos); |
| 561 | + while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) { |
| 562 | + int query_len; |
| 563 | + convert_to_string_ex(tmp); |
| 564 | + |
| 565 | + if (buffer_len < Z_STRLEN_PP(tmp)) { |
| 566 | + buffer_len = Z_STRLEN_PP(tmp); |
| 567 | + query = erealloc(query, buffer_len + 2); /* room for \n\0 */ |
| 568 | + } |
| 569 | + memcpy(query, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); |
| 570 | + query_len = Z_STRLEN_PP(tmp); |
| 571 | + if (query[query_len - 1] != '\n') { |
| 572 | + query[query_len++] = '\n'; |
| 573 | + } |
| 574 | + query[query_len] = '\0'; |
| 575 | + if (PQputCopyData(H->server, query, query_len) != 1) { |
| 576 | + efree(query); |
| 577 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "copy failed"); |
| 578 | + RETURN_FALSE; |
| 579 | + } |
| 580 | + zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos); |
| 581 | + } |
| 582 | + if (query) { |
| 583 | + efree(query); |
| 584 | + } |
| 585 | + |
| 586 | + if (PQputCopyEnd(H->server, NULL) != 1) { |
| 587 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "putcopyend failed"); |
| 588 | + RETURN_FALSE; |
| 589 | + } |
| 590 | + |
| 591 | + while ((pgsql_result = PQgetResult(H->server))) { |
| 592 | + if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) { |
| 593 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); |
| 594 | + command_failed = 1; |
| 595 | + } |
| 596 | + PQclear(pgsql_result); |
| 597 | + } |
| 598 | + |
| 599 | + RETURN_BOOL(!command_failed); |
| 600 | + } else { |
| 601 | + PQclear(pgsql_result); |
| 602 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); |
| 603 | + RETURN_FALSE; |
| 604 | + } |
| 605 | +} |
| 606 | +/* }}} */ |
| 607 | + |
| 608 | +/* {{{ proto string PDO::pgsqlCopyFromFile(string $table_name , string $filename [, string $delimiter [, string $null_as ] [, string $fields]) |
| 609 | + Returns true if the copy worked fine or false if error */ |
| 610 | +static PHP_METHOD(PDO, pgsqlCopyFromFile) |
| 611 | +{ |
| 612 | + pdo_dbh_t *dbh; |
| 613 | + pdo_pgsql_db_handle *H; |
| 614 | + |
| 615 | + char *table_name, *filename, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL; |
| 616 | + int table_name_len, filename_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len; |
| 617 | + char *query; |
| 618 | + PGresult *pgsql_result; |
| 619 | + ExecStatusType status; |
| 620 | + php_stream *stream; |
| 621 | + |
| 622 | + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|sss", |
| 623 | + &table_name, &table_name_len, &filename, &filename_len, |
| 624 | + &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) { |
| 625 | + return; |
| 626 | + } |
| 627 | + |
| 628 | + // Obtain db Handler |
| 629 | + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
| 630 | + PDO_CONSTRUCT_CHECK; |
| 631 | + |
| 632 | + stream = php_stream_open_wrapper_ex(filename, "rb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, FG(default_context)); |
| 633 | + if (!stream) { |
| 634 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to open the file"); |
| 635 | + RETURN_FALSE; |
| 636 | + } |
| 637 | + |
| 638 | + if (pg_fields) { |
| 639 | + spprintf(&query, 0, "COPY %s (%s) FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); |
| 640 | + } else { |
| 641 | + spprintf(&query, 0, "COPY %s FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); |
| 642 | + } |
| 643 | + |
| 644 | + H = (pdo_pgsql_db_handle *)dbh->driver_data; |
| 645 | + |
| 646 | + while ((pgsql_result = PQgetResult(H->server))) { |
| 647 | + PQclear(pgsql_result); |
| 648 | + } |
| 649 | + pgsql_result = PQexec(H->server, query); |
| 650 | + |
| 651 | + efree(query); |
| 652 | + |
| 653 | + if (pgsql_result) { |
| 654 | + status = PQresultStatus(pgsql_result); |
| 655 | + } else { |
| 656 | + status = (ExecStatusType) PQstatus(H->server); |
| 657 | + } |
| 658 | + |
| 659 | + if (status == PGRES_COPY_IN && pgsql_result) { |
| 660 | + char *buf; |
| 661 | + int command_failed = 0; |
| 662 | + size_t line_len = 0; |
| 663 | + |
| 664 | + PQclear(pgsql_result); |
| 665 | + while ((buf = php_stream_get_line(stream, NULL, 0, &line_len)) != NULL) { |
| 666 | + if (PQputCopyData(H->server, buf, line_len) != 1) { |
| 667 | + efree(buf); |
| 668 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "copy failed"); |
| 669 | + php_stream_close(stream); |
| 670 | + RETURN_FALSE; |
| 671 | + } |
| 672 | + efree(buf); |
| 673 | + } |
| 674 | + php_stream_close(stream); |
| 675 | + |
| 676 | + if (PQputCopyEnd(H->server, NULL) != 1) { |
| 677 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "putcopyend failed"); |
| 678 | + RETURN_FALSE; |
| 679 | + } |
| 680 | + |
| 681 | + while ((pgsql_result = PQgetResult(H->server))) { |
| 682 | + if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) { |
| 683 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); |
| 684 | + command_failed = 1; |
| 685 | + } |
| 686 | + PQclear(pgsql_result); |
| 687 | + } |
| 688 | + |
| 689 | + RETURN_BOOL(!command_failed); |
| 690 | + } else { |
| 691 | + PQclear(pgsql_result); |
| 692 | + php_stream_close(stream); |
| 693 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); |
| 694 | + RETURN_FALSE; |
| 695 | + } |
| 696 | +} |
| 697 | +/* }}} */ |
| 698 | + |
| 699 | + |
| 700 | +/* {{{ proto string PDO::pgsqlCopyToFile(string $table_name , $filename, [string $delimiter [, string $null_as [, string $fields]]]) |
| 701 | + Returns true if the copy worked fine or false if error */ |
| 702 | +static PHP_METHOD(PDO, pgsqlCopyToFile) |
| 703 | +{ |
| 704 | + pdo_dbh_t *dbh; |
| 705 | + pdo_pgsql_db_handle *H; |
| 706 | + |
| 707 | + char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL, *filename = NULL; |
| 708 | + int table_name_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len, filename_len; |
| 709 | + char *query; |
| 710 | + |
| 711 | + PGresult *pgsql_result; |
| 712 | + ExecStatusType status; |
| 713 | + |
| 714 | + php_stream *stream; |
| 715 | + |
| 716 | + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|sss", |
| 717 | + &table_name, &table_name_len, &filename, &filename_len, |
| 718 | + &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) { |
| 719 | + return; |
| 720 | + } |
| 721 | + |
| 722 | + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
| 723 | + PDO_CONSTRUCT_CHECK; |
| 724 | + |
| 725 | + H = (pdo_pgsql_db_handle *)dbh->driver_data; |
| 726 | + |
| 727 | + stream = php_stream_open_wrapper_ex(filename, "wb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, FG(default_context)); |
| 728 | + if (!stream) { |
| 729 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to open the file for writing"); |
| 730 | + RETURN_FALSE; |
| 731 | + } |
| 732 | + |
| 733 | + while ((pgsql_result = PQgetResult(H->server))) { |
| 734 | + PQclear(pgsql_result); |
| 735 | + } |
| 736 | + |
| 737 | + if (pg_fields) { |
| 738 | + spprintf(&query, 0, "COPY %s (%s) TO STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); |
| 739 | + } else { |
| 740 | + spprintf(&query, 0, "COPY %s TO STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); |
| 741 | + } |
| 742 | + pgsql_result = PQexec(H->server, query); |
| 743 | + efree(query); |
| 744 | + |
| 745 | + if (pgsql_result) { |
| 746 | + status = PQresultStatus(pgsql_result); |
| 747 | + } else { |
| 748 | + status = (ExecStatusType) PQstatus(H->server); |
| 749 | + } |
| 750 | + |
| 751 | + if (status == PGRES_COPY_OUT && pgsql_result) { |
| 752 | + PQclear(pgsql_result); |
| 753 | + while (1) { |
| 754 | + char *csv = NULL; |
| 755 | + int ret = PQgetCopyData(H->server, &csv, 0); |
| 756 | + |
| 757 | + if (ret == -1) { |
| 758 | + break; /* done */ |
| 759 | + } else if (ret > 0) { |
| 760 | + if (php_stream_write(stream, csv, ret) != ret) { |
| 761 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to write to file"); |
| 762 | + PQfreemem(csv); |
| 763 | + php_stream_close(stream); |
| 764 | + RETURN_FALSE; |
| 765 | + } else { |
| 766 | + PQfreemem(csv); |
| 767 | + } |
| 768 | + } else { |
| 769 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed: getline failed"); |
| 770 | + php_stream_close(stream); |
| 771 | + RETURN_FALSE; |
| 772 | + } |
| 773 | + } |
| 774 | + php_stream_close(stream); |
| 775 | + |
| 776 | + while ((pgsql_result = PQgetResult(H->server))) { |
| 777 | + PQclear(pgsql_result); |
| 778 | + } |
| 779 | + RETURN_TRUE; |
| 780 | + } else { |
| 781 | + php_stream_close(stream); |
| 782 | + PQclear(pgsql_result); |
| 783 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); |
| 784 | + RETURN_FALSE; |
| 785 | + } |
| 786 | +} |
| 787 | +/* }}} */ |
| 788 | + |
| 789 | +/* {{{ proto string PDO::pgsqlCopyToArray(string $table_name , [string $delimiter [, string $null_as [, string $fields]]]) |
| 790 | + Returns true if the copy worked fine or false if error */ |
| 791 | +static PHP_METHOD(PDO, pgsqlCopyToArray) |
| 792 | +{ |
| 793 | + pdo_dbh_t *dbh; |
| 794 | + pdo_pgsql_db_handle *H; |
| 795 | + |
| 796 | + char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL; |
| 797 | + int table_name_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len; |
| 798 | + char *query; |
| 799 | + |
| 800 | + PGresult *pgsql_result; |
| 801 | + ExecStatusType status; |
| 802 | + |
| 803 | + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sss", |
| 804 | + &table_name, &table_name_len, |
| 805 | + &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) { |
| 806 | + return; |
| 807 | + } |
| 808 | + |
| 809 | + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
| 810 | + PDO_CONSTRUCT_CHECK; |
| 811 | + |
| 812 | + H = (pdo_pgsql_db_handle *)dbh->driver_data; |
| 813 | + |
| 814 | + while ((pgsql_result = PQgetResult(H->server))) { |
| 815 | + PQclear(pgsql_result); |
| 816 | + } |
| 817 | + |
| 818 | + if (pg_fields) { |
| 819 | + spprintf(&query, 0, "COPY %s (%s) TO STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); |
| 820 | + } else { |
| 821 | + spprintf(&query, 0, "COPY %s TO STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); |
| 822 | + } |
| 823 | + pgsql_result = PQexec(H->server, query); |
| 824 | + efree(query); |
| 825 | + |
| 826 | + if (pgsql_result) { |
| 827 | + status = PQresultStatus(pgsql_result); |
| 828 | + } else { |
| 829 | + status = (ExecStatusType) PQstatus(H->server); |
| 830 | + } |
| 831 | + |
| 832 | + if (status == PGRES_COPY_OUT && pgsql_result) { |
| 833 | + PQclear(pgsql_result); |
| 834 | + array_init(return_value); |
| 835 | + |
| 836 | + while (1) { |
| 837 | + char *csv = NULL; |
| 838 | + int ret = PQgetCopyData(H->server, &csv, 0); |
| 839 | + if (ret == -1) { |
| 840 | + break; /* copy done */ |
| 841 | + } else if (ret > 0) { |
| 842 | + add_next_index_stringl(return_value, csv, ret, 1); |
| 843 | + PQfreemem(csv); |
| 844 | + } else { |
| 845 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed: getline failed"); |
| 846 | + RETURN_FALSE; |
| 847 | + } |
| 848 | + } |
| 849 | + |
| 850 | + while ((pgsql_result = PQgetResult(H->server))) { |
| 851 | + PQclear(pgsql_result); |
| 852 | + } |
| 853 | + } else { |
| 854 | + PQclear(pgsql_result); |
| 855 | + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); |
| 856 | + RETURN_FALSE; |
| 857 | + } |
| 858 | +} |
| 859 | +/* }}} */ |
| 860 | + |
| 861 | + |
499 | 862 | /* {{{ proto string PDO::pgsqlLOBCreate()
|
500 | 863 | Creates a new large object, returning its identifier. Must be called inside a transaction. */
|
501 | 864 | static PHP_METHOD(PDO, pgsqlLOBCreate)
|
@@ -608,6 +971,10 @@ static const zend_function_entry dbh_methods[] = {
|
608 | 971 | PHP_ME(PDO, pgsqlLOBCreate, NULL, ZEND_ACC_PUBLIC)
|
609 | 972 | PHP_ME(PDO, pgsqlLOBOpen, NULL, ZEND_ACC_PUBLIC)
|
610 | 973 | PHP_ME(PDO, pgsqlLOBUnlink, NULL, ZEND_ACC_PUBLIC)
|
| 974 | + PHP_ME(PDO, pgsqlCopyFromArray, NULL, ZEND_ACC_PUBLIC) |
| 975 | + PHP_ME(PDO, pgsqlCopyFromFile, NULL, ZEND_ACC_PUBLIC) |
| 976 | + PHP_ME(PDO, pgsqlCopyToArray, NULL, ZEND_ACC_PUBLIC) |
| 977 | + PHP_ME(PDO, pgsqlCopyToFile, NULL, ZEND_ACC_PUBLIC) |
611 | 978 | {NULL, NULL, NULL}
|
612 | 979 | };
|
613 | 980 |
|
|
0 commit comments