Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -601,6 +601,7 @@ |
602 | 602 | * User::isValidPassword now only returns boolean results, User::getPasswordValidity |
603 | 603 | can be used to get an error message string |
604 | 604 | * The error message shown in Special:ChangePassword now parses wiki markup |
| 605 | +* (bug 18909) Add missing Postgres INSERT SELECT wrapper |
605 | 606 | |
606 | 607 | == API changes in 1.16 == |
607 | 608 | |
Index: trunk/phase3/includes/db/DatabasePostgres.php |
— | — | @@ -873,6 +873,81 @@ |
874 | 874 | |
875 | 875 | } |
876 | 876 | |
| 877 | + /** |
| 878 | + * INSERT SELECT wrapper |
| 879 | + * $varMap must be an associative array of the form array( 'dest1' => 'source1', ...) |
| 880 | + * Source items may be literals rather then field names, but strings should be quoted with Database::addQuotes() |
| 881 | + * $conds may be "*" to copy the whole table |
| 882 | + * srcTable may be an array of tables. |
| 883 | + * @todo FIXME: implement this a little better (seperate select/insert)? |
| 884 | + */ |
| 885 | + function insertSelect( $destTable, $srcTable, $varMap, $conds, $fname = 'DatabasePostgres::insertSelect', |
| 886 | + $insertOptions = array(), $selectOptions = array() ) |
| 887 | + { |
| 888 | + $destTable = $this->tableName( $destTable ); |
| 889 | + |
| 890 | + // If IGNORE is set, we use savepoints to emulate mysql's behavior |
| 891 | + $ignore = in_array( 'IGNORE', $insertOptions ) ? 'mw' : ''; |
| 892 | + |
| 893 | + if( is_array( $insertOptions ) ) { |
| 894 | + $insertOptions = implode( ' ', $insertOptions ); |
| 895 | + } |
| 896 | + if( !is_array( $selectOptions ) ) { |
| 897 | + $selectOptions = array( $selectOptions ); |
| 898 | + } |
| 899 | + list( $startOpts, $useIndex, $tailOpts ) = $this->makeSelectOptions( $selectOptions ); |
| 900 | + if( is_array( $srcTable ) ) { |
| 901 | + $srcTable = implode( ',', array_map( array( &$this, 'tableName' ), $srcTable ) ); |
| 902 | + } else { |
| 903 | + $srcTable = $this->tableName( $srcTable ); |
| 904 | + } |
| 905 | + |
| 906 | + // If we are not in a transaction, we need to be for savepoint trickery |
| 907 | + $didbegin = 0; |
| 908 | + if ( $ignore ) { |
| 909 | + if( !$this->mTrxLevel ) { |
| 910 | + $this->begin(); |
| 911 | + $didbegin = 1; |
| 912 | + } |
| 913 | + $olde = error_reporting( 0 ); |
| 914 | + $numrowsinserted = 0; |
| 915 | + pg_query( $this->mConn, "SAVEPOINT $ignore"); |
| 916 | + } |
| 917 | + |
| 918 | + $sql = "INSERT INTO $destTable (" . implode( ',', array_keys( $varMap ) ) . ')' . |
| 919 | + " SELECT $startOpts " . implode( ',', $varMap ) . |
| 920 | + " FROM $srcTable $useIndex"; |
| 921 | + |
| 922 | + if ( $conds != '*') { |
| 923 | + $sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND ); |
| 924 | + } |
| 925 | + |
| 926 | + $sql .= " $tailOpts"; |
| 927 | + |
| 928 | + $res = (bool)$this->query( $sql, $fname, $ignore ); |
| 929 | + if( $ignore ) { |
| 930 | + $bar = pg_last_error(); |
| 931 | + if( $bar != false ) { |
| 932 | + pg_query( $this->mConn, "ROLLBACK TO $ignore" ); |
| 933 | + } else { |
| 934 | + pg_query( $this->mConn, "RELEASE $ignore" ); |
| 935 | + $numrowsinserted++; |
| 936 | + } |
| 937 | + $olde = error_reporting( $olde ); |
| 938 | + if( $didbegin ) { |
| 939 | + $this->commit(); |
| 940 | + } |
| 941 | + |
| 942 | + // Set the affected row count for the whole operation |
| 943 | + $this->mAffectedRows = $numrowsinserted; |
| 944 | + |
| 945 | + // IGNORE always returns true |
| 946 | + return true; |
| 947 | + } |
| 948 | + |
| 949 | + return $res; |
| 950 | + } |
| 951 | + |
877 | 952 | function tableName( $name ) { |
878 | 953 | # Replace reserved words with better ones |
879 | 954 | switch( $name ) { |