Changeset 260
- Timestamp:
- 10/23/07 02:11:30 (9 months ago)
- Files:
-
- branches/2.3/classes/phing/tasks/defaults.properties (modified) (1 diff)
- branches/2.3/classes/phing/tasks/ext/pdo (added)
- branches/2.3/classes/phing/tasks/ext/pdo/PDOResultFormatter.php (added)
- branches/2.3/classes/phing/tasks/ext/pdo/PDOSQLExecFormatterElement.php (added)
- branches/2.3/classes/phing/tasks/ext/pdo/PDOSQLExecTask.php (moved) (moved from branches/2.3/classes/phing/tasks/ext/PDOSQLExecTask.php) (22 diffs)
- branches/2.3/classes/phing/tasks/ext/pdo/PDOTask.php (moved) (moved from branches/2.3/classes/phing/tasks/ext/PDOTask.php)
- branches/2.3/classes/phing/tasks/ext/pdo/PlainPDOResultFormatter.php (added)
- branches/2.3/classes/phing/tasks/ext/pdo/XMLPDOResultFormatter.php (added)
- branches/2.3/docs/phing_guide/book/chapters/appendixes/AppendixC-OptionalTasks.html (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/2.3/classes/phing/tasks/defaults.properties
r259 r260 45 45 46 46 creole=phing.tasks.ext.creole.CreoleSQLExecTask 47 pdo=phing.tasks.ext. PDOSQLExecTask47 pdo=phing.tasks.ext.pdo.PDOSQLExecTask 48 48 package-as-path=phing.tasks.ext.PackageAsPathTask 49 49 smarty=phing.tasks.ext.SmartyTask branches/2.3/classes/phing/tasks/ext/pdo/PDOSQLExecTask.php
r256 r260 20 20 */ 21 21 22 require_once 'phing/tasks/ext/ PDOTask.php';22 require_once 'phing/tasks/ext/pdo/PDOTask.php'; 23 23 include_once 'phing/system/io/StringReader.php'; 24 include_once 'phing/tasks/ext/pdo/PDOSQLExecFormatterElement.php'; 24 25 25 26 /** … … 54 55 class PDOSQLExecTask extends PDOTask { 55 56 57 /** 58 * Count of how many statements were executed successfully. 59 * @var int 60 */ 56 61 private $goodSql = 0; 62 63 /** 64 * Count of total number of SQL statements. 65 * @var int 66 */ 57 67 private $totalSql = 0; 58 68 … … 62 72 /** 63 73 * Database connection 74 * @var PDO 64 75 */ 65 76 private $conn = null; 66 77 67 78 /** 68 * files to load 79 * Files to load 80 * @var array FileSet[] 69 81 */ 70 82 private $filesets = array(); 71 83 72 84 /** 85 * Formatter elements. 86 * @var array PDOSQLExecFormatterElement[] 87 */ 88 private $formatters = array(); 89 90 /** 73 91 * SQL statement 74 */ 75 private $statement = null; 92 * @var PDOStatement 93 */ 94 private $statement; 76 95 77 96 /** 78 97 * SQL input file 79 */ 80 private $srcFile = null; 98 * @var PhingFile 99 */ 100 private $srcFile; 81 101 82 102 /** 83 103 * SQL input command 104 * @var string 84 105 */ 85 106 private $sqlCommand = ""; … … 91 112 92 113 /** 93 * SQL Statement delimiter 114 * SQL Statement delimiter (for parsing files) 115 * @var string 94 116 */ 95 117 private $delimiter = ";"; … … 100 122 */ 101 123 private $delimiterType = "normal"; // can't use constant just defined 102 103 /**104 * Print SQL results.105 */106 private $print = false;107 108 /**109 * Print header columns.110 */111 private $showheaders = true;112 113 /**114 * Results Output file.115 */116 private $output = null;117 118 124 119 125 /** … … 128 134 129 135 /** 130 * Append to an existing file or overwrite it?131 */132 private $append = false;133 134 /**135 136 * Fetch mode for PDO select queries. 136 137 * @var int … … 159 160 public function addFileset(FileSet $set) { 160 161 $this->filesets[] = $set; 162 } 163 164 /** 165 * Creates a new PDOSQLExecFormatterElement for <formatter> element. 166 * @return PDOSQLExecFormatterElement 167 */ 168 public function createFormatter() 169 { 170 $fe = new PDOSQLExecFormatterElement($this); 171 $this->formatters[] = $fe; 172 return $fe; 161 173 } 162 174 … … 204 216 $this->delimiterType = $delimiterType; 205 217 } 206 207 /**208 * Set the print flag.209 *210 * @param boolean $print211 */212 public function setPrint($print)213 {214 $this->print = (boolean) $print;215 }216 217 /**218 * Print headers for result sets from the219 * statements; optional, default true.220 * @param boolean $showheaders221 */222 public function setShowheaders($showheaders) {223 $this->showheaders = (boolean) $showheaders;224 }225 226 /**227 * Set the output file;228 * optional, defaults to the console.229 * @param PhingFile $output230 */231 public function setOutput(PhingFile $output) {232 $this->output = $output;233 }234 235 /**236 * whether output should be appended to or overwrite237 * an existing file. Defaults to false.238 * @param $append239 */240 public function setAppend($append) {241 $this->append = (boolean) $append;242 }243 244 218 245 219 /** … … 268 242 269 243 /** 244 * Gets a default output writer for this task. 245 * @return Writer 246 */ 247 private function getDefaultOutput() 248 { 249 return new LogWriter($this); 250 } 251 252 /** 270 253 * Load the sql file and then execute it 271 254 * @throws BuildException … … 277 260 if ($this->fetchMode === null) { 278 261 $this->fetchMode = PDO::FETCH_BOTH; 262 } 263 264 // Initialize the formatters here. This ensures that any parameters passed to the formatter 265 // element get passed along to the actual formatter object 266 foreach($this->formatters as $fe) { 267 $fe->prepare(); 279 268 } 280 269 … … 324 313 $this->statement = null; 325 314 326 $out = null; 315 // Initialize the formatters. 316 $this->initFormatters(); 327 317 328 318 try { 329 330 if ($this->output !== null) {331 $this->log("Opening output file " . $this->output, Project::MSG_VERBOSE);332 $out = new BufferedWriter(new FileWriter($this->output->getAbsolutePath(), $this->append));333 }334 319 335 320 // Process all transactions … … 339 324 $this->conn->beginTransaction(); 340 325 } 341 $this->transactions[$i]->runTransaction( $out);326 $this->transactions[$i]->runTransaction(); 342 327 if (!$this->isAutocommit()) { 343 328 $this->log("Commiting transaction", Project::MSG_VERBOSE); … … 345 330 } 346 331 } 347 if ($out) $out->close();348 332 } catch (Exception $e) { 349 if ($out) $out->close();350 333 throw $e; 351 334 } … … 354 337 try { 355 338 $this->conn->rollback(); 356 } catch ( SQLException $ex) {}339 } catch (PDOException $ex) {} 357 340 } 358 341 throw new BuildException($e->getMessage(), $this->location); 359 } catch ( SQLException $e){342 } catch (PDOException $e){ 360 343 if (!$this->isAutocommit() && $this->conn !== null && $this->onError == "abort") { 361 344 try { 362 345 $this->conn->rollback(); 363 } catch ( SQLException $ex) {}346 } catch (PDOException $ex) {} 364 347 } 365 348 throw new BuildException($e->getMessage(), $this->location); 366 349 } 350 351 // Close the formatters. 352 $this->closeFormatters(); 367 353 368 354 $this->log($this->goodSql . " of " . $this->totalSql . 369 355 " SQL statements executed successfully"); 356 370 357 } catch (Exception $e) { 371 358 $this->transactions = $savedTransaction; … … 382 369 /** 383 370 * read in lines and execute them 384 * @throws SQLException, IOException385 */ 386 public function runStatements(Reader $reader , Writer $out = null) {371 * @throws PDOException, IOException 372 */ 373 public function runStatements(Reader $reader) { 387 374 $sql = ""; 388 375 $line = ""; … … 420 407 && $line == $this->delimiter) { 421 408 $this->log("SQL: " . $sql, Project::MSG_VERBOSE); 422 $this->execSQL(StringHelper::substring($sql, 0, strlen($sql) - strlen($this->delimiter) - 1) , $out);409 $this->execSQL(StringHelper::substring($sql, 0, strlen($sql) - strlen($this->delimiter) - 1)); 423 410 $sql = ""; 424 411 } … … 427 414 // Catch any statements not followed by ; 428 415 if ($sql !== "") { 429 $this->execSQL($sql , $out);430 } 431 } catch ( SQLException $e) {416 $this->execSQL($sql); 417 } 418 } catch (PDOException $e) { 432 419 throw new BuildException("Error running statements", $e); 433 420 } 434 421 } 435 422 436 423 /** 437 424 * Whether the passed-in SQL statement is a SELECT statement. … … 442 429 * @return boolean Whether specified SQL looks like a SELECT query. 443 430 */ 444 protected function isSelectSql($sql)445 {446 $sql = trim($sql);447 return (stripos($sql, 'select') === 0 && stripos($sql, 'select into ') !== 0);448 }449 431 protected function isSelectSql($sql) 432 { 433 $sql = trim($sql); 434 return (stripos($sql, 'select') === 0 && stripos($sql, 'select into ') !== 0); 435 } 436 450 437 /** 451 438 * Exec the sql statement. 452 * @throws SQLException 453 */ 454 protected function execSQL($sql, Writer $out = null) { 439 * @throws PDOException 440 */ 441 protected function execSQL($sql) { 442 455 443 // Check and ignore empty statements 456 444 if (trim($sql) == "") { … … 460 448 try { 461 449 $this->totalSql++; 462 463 # FIXME - currently, this only works for update statements 450 464 451 $this->statement = $this->conn->prepare($sql); 465 452 $this->statement->execute(); 466 453 $this->log($this->statement->rowCount() . " rows affected", Project::MSG_VERBOSE); 467 468 if ($this->isSelectSql($sql) && $this->print) { 469 $this->printResults($out); 470 } else { 471 $this->statement->closeCursor(); 472 } 473 454 455 $this->processResults(); 456 457 $this->statement->closeCursor(); 458 $this->statement = null; 459 474 460 $this->goodSql++; 475 461 476 } catch ( SQLException $e) {462 } catch (PDOException $e) { 477 463 $this->log("Failed to execute: " . $sql, Project::MSG_ERR); 478 464 if ($this->onError != "continue") { … … 484 470 485 471 /** 486 * print any results in the statement. 487 * @throw SQLException 488 */ 489 protected function printResults(Writer $out = null) { 490 491 $this->log("Processing new result set.", Project::MSG_VERBOSE); 492 493 $line = ""; 494 495 $colsprinted = false; 496 497 while ($row = $this->statement->fetch($this->fetchMode)) { 498 499 if (!$colsprinted && $this->showheaders) { 500 $first = true; 501 foreach($row as $fieldName => $ignore) { 502 if ($first) $first = false; else $line .= ","; 503 $line .= $fieldName; 504 } 505 if ($out !== null) { 506 $out->write($line); 507 $out->newLine(); 508 } else { 509 print($line.PHP_EOL); 510 } 511 $line = ""; 512 $colsprinted = true; 513 } // if show headers 514 515 $first = true; 516 foreach($row as $columnValue) { 517 518 if ($columnValue != null) { 519 $columnValue = trim($columnValue); 520 } 521 522 if ($first) { 523 $first = false; 524 } else { 525 $line .= ","; 526 } 527 $line .= $columnValue; 528 } 529 530 if ($out !== null) { 531 $out->write($line); 532 $out->newLine(); 533 } else { 534 print($line . PHP_EOL); 535 } 536 $line = ""; 537 538 } 539 540 // Addresses some issues w/ PDO 541 // See: http://verens.com/archives/2006/10/19/pdosqlite-gotcha/ 542 $this->statement = null; 543 544 if ($out !== null) { 545 $out->newLine(); 546 } else { 547 print(PHP_EOL); 548 } 472 * Returns configured PDOResultFormatter objects (which were created from PDOSQLExecFormatterElement objects). 473 * @return array PDOResultFormatter[] 474 */ 475 protected function getConfiguredFormatters() 476 { 477 $formatters = array(); 478 foreach ($this->formatters as $fe) { 479 $formatters[] = $fe->getFormatter(); 480 } 481 return $formatters; 482 } 483 484 /** 485 * Initialize the formatters. 486 */ 487 protected function initFormatters() { 488 $formatters = $this->getConfiguredFormatters(); 489 foreach ($formatters as $formatter) { 490 $formatter->initialize(); 491 } 492 493 } 494 495 /** 496 * Run cleanup and close formatters. 497 */ 498 protected function closeFormatters() { 499 $formatters = $this->getConfiguredFormatters(); 500 foreach ($formatters as $formatter) { 501 $formatter->close(); 502 } 503 } 504 505 /** 506 * Passes results from query to any formatters. 507 * @throw PDOException 508 */ 509 protected function processResults() { 510 511 try { 512 513 $this->log("Processing new result set.", Project::MSG_VERBOSE); 514 515 $formatters = $this->getConfiguredFormatters(); 516 517 while ($row = $this->statement->fetch($this->fetchMode)) { 518 foreach ($formatters as $formatter) { 519 $formatter->processRow($row); 520 } 521 } 522 523 } catch (Exception $x) { 524 $this->log("Error processing reults: " . $x->getMessage(), Project::MSG_ERR); 525 foreach ($formatters as $formatter) { 526 $formatter->close(); 527 } 528 throw $x; 529 } 530 549 531 } 550 532 } 551 552 533 553 534 /** … … 580 561 581 562 /** 582 * @throws IOException, SQLException583 */ 584 public function runTransaction( $out = null)563 * @throws IOException, PDOException 564 */ 565 public function runTransaction() 585 566 { 586 567 if (!empty($this->tSqlCommand)) { 587 568 $this->parent->log("Executing commands", Project::MSG_INFO); 588 $this->parent->runStatements(new StringReader($this->tSqlCommand) , $out);569 $this->parent->runStatements(new StringReader($this->tSqlCommand)); 589 570 } 590 571 … … 593 574 Project::MSG_INFO); 594 575 $reader = new FileReader($this->tSrcFile); 595 $this->parent->runStatements($reader , $out);576 $this->parent->runStatements($reader); 596 577 $reader->close(); 597 578 } branches/2.3/docs/phing_guide/book/chapters/appendixes/AppendixC-OptionalTasks.html
r240 r260 518 518 <fileset dir="sqlfiles"> 519 519 <include name="*.sql"/> 520 </fileset> 521 </pdo> 520 </fileset><br /></pdo> 522 521 </pre> 523 522 524 523 <pre><pdo url="mysql:host=localhost;dbname=test" userid="username" password="password"> 525 524 <transaction src="path/to/sqlfile.sql"/> 525 <formatter type="plain" outfile="path/to/output.txt"/> 526 526 </pdo> 527 527 </pre> … … 579 579 <td>The action to perform on error (continue, stop, or abort)</td> 580 580 <td>abort</td> 581 <td>No</td>582 </tr>583 <tr>584 <td>output</td>585 <td>File</td>586 <td>The file to which output should be logged.</td>587 <td>none</td>588 <td>No</td>589 </tr>590 <tr>591 <td>print</td>592 <td>Boolean</td>593 <td>Whether to print results of query.</td>594 <td>false</td>595 <td>No</td>596 </tr>597 <tr>598 <td>showheaders</td>599 <td>Boolean</td>600 <td>Whether to show column headers.</td>601 <td>false</td>602 581 <td>No</td> 603 582 </tr> … … 628 607 <li>fileset 629 608 <p>Files containing SQL statements.</p> 609 </li> 610 <li>formatter 611 <p>The results of any queries that are executed can be printed in different formats. 612 Output will always be sent to a file, unless you set the <em>usefile</em> attribute to <em>false</em>. 613 The path to the output file file can be specified by the <em>outfile</em> attribute; there is a default filename that 614 will be returned by the formatter if no output file is specified.</p> 615 <p>There are three predefined formatters - one prints the query results in XML format, 616 the other emits plain text. Custom formatters that 617 extend phing.tasks.pdo.PDOResultFormatter can be specified.</p> 618 <h3>Attributes</h3> 619 <table> 620 <thead> 621 <tr> 622 <th>Name</th> 623 <th>Type</th> 624 <th>Description</th> 625 <th>Default</th> 626 <th>Required</th> 627 </tr> 628 </thead> 629 <tbody> 630 <tr> 631 <td>type</td> 632 <td>String</td> 633 <td> Use a predefined formatter (either <em>xml</em>, <em>plain</em>, or <em>brief</em>). </td> 634 <td>n/a</td> 635 <td rowspan="2">One of these attributes is required. </td> 636 </tr> 637 <tr> 638 <td>classname</td> 639 <td>String</td> 640 <td> Name of a custom formatter class (must extend phing.tasks.ext.pdo.PDOResultFormatter). </td> 641 <td>n/a</td> 642 </tr> 643 <tr> 644 <td>usefile</td> 645 <td>Boolean</td> 646 <td> Boolean that determines whether output should be sent to a file. </td> 647 <td>true</td> 648 <td>No</td> 649 </tr> 650 <tr> 651 <td>outfile</td> 652 <td>File</td> 653 <td>Path to file in which to store result. </td> 654 <td>Depends on formatter</td> 655 <td>No</td> 656 </tr> 657 <tr> 658 <td>showheaders</td> 659 <td>Boolean</td> 660 <td>(only applies to plain formatter) Whether to show column headers.</td> 661 <td>false</td> 662 <td>No</td> 663 </tr> 664 <tr> 665 <td>coldelim</td> 666 <td>String</td> 667 <td>(only applies to plain formatter) The column delimiter.</td> 668 <td>,</td> 669 <td>No</td> 670 </tr> 671 <tr> 672 <td>rowdelim</td> 673 <td>String</td> 674 <td>(only applies to plain formatter) The row delimiter.</td> 675 <td>\n</td> 676 <td>No</td> 677 </tr> 678 <tr> 679 <td>encoding</td> 680 <td>String</td> 681 <td>(only applies to XML formatter) The xml document encoding.</td> 682 <td>(PHP default)</td> 683 <td>No</td> 684 </tr> 685 <tr> 686 <td>formatoutput</td> 687 <td>Boolean</td> 688 <td>(only applies to XML formatter) Whether to format XML output.</td> 689 <td>true</td> 690 <td>No</td> 691 </tr> 692 </tbody> 693 </table> 694 <h3>Examples</h3> 695 <pre><pdo url="pgsql:host=localhost dbname=test"> 696 <fileset dir="sqlfiles"> 697 <include name="*.sql"/> 698 </fileset> 699 700 <!-- xml formatter --> 701 <formatter type="xml" output="output.xml"/> 702 703 <!-- custom formatter --> 704 <formatter classname="path.to.CustomFormatterClass"> 705 <param name="someClassAttrib" value="some-value"/> 706 </formatter> 707 708 <!-- No output file + usefile=false means it goes to phing log --> 709 <formatter type="plain" usefile="false" /><br /></pdo> 710 </pre> 711 630 712 </li> 631 713 </ul>
