[ Index ]
 

Code source de b2evolution 2.1.0-beta

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

/blogs/inc/_core/model/db/ -> _db.class.php (source)

   1  <?php
   2  /**

   3   * This file implements the DB class.

   4   *

   5   * Based on ezSQL - Class to make it very easy to deal with MySQL database connections.

   6   * b2evo Additions:

   7   * - nested transactions

   8   * - symbolic table names

   9   * - query log

  10   * - get_list

  11   * - dynamic extension loading

  12   * - Debug features (EXPLAIN...)

  13   * and more...

  14   *

  15   * This file is part of the b2evolution/evocms project - {@link http://b2evolution.net/}.

  16   * See also {@link http://sourceforge.net/projects/evocms/}.

  17   *

  18   * @copyright (c)2003-2007 by Francois PLANQUE - {@link http://fplanque.net/}.

  19   * Parts of this file are copyright (c)2004 by Justin Vincent - {@link http://php.justinvincent.com}

  20   * Parts of this file are copyright (c)2004-2005 by Daniel HAHLER - {@link http://thequod.de/contact}.

  21   *

  22   * {@internal License choice

  23   * - If you have received this file as part of a package, please find the license.txt file in

  24   *   the same folder or the closest folder above for complete license terms.

  25   * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)

  26   *   then you must choose one of the following licenses before using the file:

  27   *   - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php

  28   *   - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php

  29   * }}

  30   *

  31   * {@internal Origin:

  32   * This file is based on the following package (excerpt from ezSQL's readme.txt):

  33   * =======================================================================

  34   * Author:  Justin Vincent (justin@visunet.ie)

  35   * Web:      http://php.justinvincent.com

  36   * Name:      ezSQL

  37   * Desc:      Class to make it very easy to deal with database connections.

  38   * License: FREE / Donation (LGPL - You may do what you like with ezSQL - no exceptions.)

  39   * =======================================================================

  40   * A $10 donation has been made to Justin VINCENT on behalf of the b2evolution team.

  41   * The package has been relicensed as GPL based on

  42   * "You may do what you like with ezSQL - no exceptions."

  43   * 2004-10-14 (email): Justin VINCENT grants Francois PLANQUE the right to relicense

  44   * this modified class under other licenses. "Just include a link to where you got it from."

  45   * }}

  46   *

  47   * {@internal Open Source relicensing agreement:

  48   * Daniel HAHLER grants Francois PLANQUE the right to license

  49   * Daniel HAHLER's contributions to this file and the b2evolution project

  50   * under any OSI approved OSS license (http://www.opensource.org/licenses/).

  51   * }}

  52   *

  53   * @package evocore

  54   *

  55   * {@internal Below is a list of authors who have contributed to design/coding of this file: }}

  56   * @author blueyed: Daniel HAHLER

  57   * @author fplanque: Francois PLANQUE

  58   * @author Justin VINCENT

  59   *

  60   * @version $Id: _db.class.php,v 1.2 2007/10/01 19:02:23 fplanque Exp $

  61   * @todo transaction support

  62   */
  63  if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
  64  
  65  /**

  66   * ezSQL Constants

  67   */
  68  define( 'EZSQL_VERSION', '1.25' );
  69  define( 'OBJECT', 'OBJECT', true );
  70  define( 'ARRAY_A', 'ARRAY_A', true);
  71  define( 'ARRAY_N', 'ARRAY_N', true);
  72  
  73  if( ! function_exists( 'mysql_real_escape_string' ) )
  74  { // Function only available since PHP 4.3.0
  75  	function mysql_real_escape_string( $unescaped_string )
  76      {
  77          return mysql_escape_string( $unescaped_string );
  78      }
  79  }
  80  
  81  /**

  82   * The Main Class

  83   *

  84   * @package evocore

  85   */
  86  class DB
  87  {
  88      /**

  89       * Show/Print errors?

  90       * @var boolean

  91       */
  92      var $show_errors = true;
  93      /**

  94       * Halt on errors?

  95       * @var boolean

  96       */
  97      var $halt_on_error = true;
  98      /**

  99       * Has an error occured?

 100       * @var boolean

 101       */
 102      var $error = false;
 103      /**

 104       * Number of done queries.

 105       * @var integer

 106       */
 107      var $num_queries = 0;
 108      /**

 109       * last query SQL string

 110       * @var string

 111       */
 112      var $last_query = '';
 113      /**

 114       * last DB error string

 115       * @var string

 116       */
 117      var $last_error = '';
 118  
 119      /**

 120       * Last insert ID

 121       * @var integer

 122       */
 123      var $insert_id = 0;
 124  
 125      /**

 126       * Last query's resource

 127       * @access protected

 128       * @var resource

 129       */
 130      var $result;
 131  
 132      /**

 133       * Last result's rows

 134       * @var array

 135       */
 136      var $last_result;
 137  
 138      /**

 139       * Number of rows in result set (after a select)

 140       */
 141      var $num_rows = 0;
 142  
 143      /**

 144       * Number of rows affected by insert, delete, update or replace

 145       */
 146      var $rows_affected = 0;
 147  
 148      /**

 149       * Aliases that will be replaced in queries:

 150       */
 151      var $dbaliases = array();
 152      /**

 153       * Strings that will replace the aliases in queries:

 154       */
 155      var $dbreplaces = array();
 156  
 157      /**

 158       * CREATE TABLE options.

 159       *

 160       * This gets appended to every "CREATE TABLE" query.

 161       *

 162       * Edit those if you have control over you MySQL server and want a more professional

 163       * database than what is commonly offered by popular hosting providers.

 164       *

 165       * Recommended settings: ' ENGINE=InnoDB '

 166       * Development settings: ' ENGINE=InnoDB DEFAULT CHARSET=utf8 '

 167       * @var string

 168       */
 169      var $table_options = '';
 170  
 171      /**

 172       * Use transactions in DB?

 173       *

 174       * You need to use InnoDB in order to enable this.  See the {@link $db_config "table_options" key}.

 175       */
 176      var $use_transactions = false;
 177  
 178      /**

 179       * How many transactions are currently nested?

 180       */
 181      var $transaction_nesting_level = 0;
 182  
 183      /**

 184       * Rememeber if we have to rollback at the end of a nested transaction construct

 185       */
 186      var $rollback_nested_transaction = false;
 187  
 188      /**

 189       * MySQL Database handle

 190       * @var object

 191       */
 192      var $dbhandle;
 193  
 194      /**

 195       * Database username

 196       * @var string

 197       */
 198      var $dbuser;
 199  
 200      /**

 201       * Database username's password

 202       * @var string

 203       */
 204      var $dbpassword;
 205  
 206      /**

 207       * Database name

 208       * @var string

 209       * @see select()

 210       */
 211      var $dbname;
 212  
 213      /**

 214       * Database hostname

 215       * @var string

 216       */
 217      var $dbhost = 'localhost';
 218  
 219      /**

 220       * Current connection charset

 221       * @var string

 222       * @see DB::set_connection_charset()

 223       */
 224      var $connection_charset;
 225  
 226  
 227      // DEBUG:

 228  
 229    /**

 230     * Do we want to log queries?

 231       * This gets set according to {@link $debug}, if it's set.

 232       * @todo fp> get rid of this var, use $debug only

 233     * @var boolean

 234     */
 235      var $log_queries;
 236  
 237      /**

 238       * Log of queries:

 239       * @var array

 240       */
 241      var $queries = array();
 242  
 243      /**

 244       * Do we want to explain joins?

 245       * This requires {@link DB::$log_queries} to be true.

 246       * @var boolean

 247       */
 248      var $debug_explain_joins = false;
 249  
 250      /**

 251       * Do we want to output a function backtrace for every query?

 252       * Number of stack entries to show (from last to first) (Default: 0); true means 'all'.

 253       *

 254       * This requires {@link DB::$log_queries} to be true.

 255       *

 256       * @var integer

 257       */
 258      var $debug_dump_function_trace_for_queries = 0;
 259  
 260      /**

 261       * Number of rows we want to dump in debug output (0 disables it)

 262       * This requires {@link DB::$log_queries} to be true.

 263       * @var integer

 264       */
 265      var $debug_dump_rows = 0;
 266  
 267      /**

 268       * Time in seconds that is considered a fast query (green).

 269       * @var float

 270       * @see dump_queries()

 271       */
 272      var $query_duration_fast = 0.05;
 273  
 274      /**

 275       * Time in seconds that is considered a slow query (red).

 276       * @var float

 277       * @see dump_queries()

 278       */
 279      var $query_duration_slow = 0.3;
 280  
 281  
 282      /**

 283       * DB Constructor

 284       *

 285       * Connects to the server and selects a database.

 286       *

 287       * @param array An array of parameters.

 288       *   Manadatory:

 289       *    - 'user': username to connect with

 290       *    - 'password': password to connect with

 291       *    OR

 292       *    - 'handle': a MySQL Database handle (from a previous {@link mysql_connect()})

 293       *   Optional:

 294       *    - 'name': the name of the default database, see {@link DB::select()}

 295       *    - 'host': host of the database; Default: 'localhost'

 296       *    - 'show_errors': Display SQL errors? (true/false); Default: don't change member default ({@link $show_errors})

 297       *    - 'halt_on_error': Halt on error? (true/false); Default: don't change member default ({@link $halt_on_error})

 298       *    - 'table_options': sets {@link $table_options}

 299       *    - 'use_transactions': sets {@link $use_transactions}

 300       *    - 'aliases': Aliases for tables (array( alias => table name )); Default: no aliases.

 301       *    - 'new_link': create a new link to the DB, even if there was a mysql_connect() with

 302       *       the same params before. (requires PHP 4.2)

 303       *    - 'client_flags': optional settings like compression or SSL encryption. See {@link http://www.php.net/manual/en/ref.mysql.php#mysql.client-flags}.

 304       *       (requires PHP 4.3)

 305       */
 306      function DB( $params )
 307      {
 308          global $debug;
 309  
 310          // Mandatory parameters:

 311          if( isset( $params['handle'] ) )
 312          { // DB-Link provided:
 313              $this->dbhandle = $params['handle'];
 314          }
 315          else
 316          {
 317              $this->dbuser = $params['user'];
 318              $this->dbpassword = $params['password'];
 319          }
 320  
 321          // Optional parameters (Allow overriding through $params):

 322          if( isset($params['name']) ) $this->dbname = $params['name'];
 323          if( isset($params['host']) ) $this->dbhost = $params['host'];
 324          if( isset($params['show_errors']) ) $this->show_errors = $params['show_errors'];
 325          if( isset($params['halt_on_error']) ) $this->halt_on_error = $params['halt_on_error'];
 326          if( isset($params['table_options']) ) $this->table_options = $params['table_options'];
 327          if( isset($params['use_transactions']) ) $this->use_transactions = $params['use_transactions'];
 328          if( isset($params['debug_dump_rows']) ) $this->debug_dump_rows = $params['debug_dump_rows']; // Nb of rows to dump

 329          if( isset($params['debug_explain_joins']) ) $this->debug_explain_joins = $params['debug_explain_joins'];
 330          if( isset($params['debug_dump_function_trace_for_queries']) ) $this->debug_dump_function_trace_for_queries = $params['debug_dump_function_trace_for_queries'];
 331  
 332          if( isset($debug) && ! isset($this->log_queries) )
 333          { // $log_queries follows $debug and respects subclasses, which may define it:
 334              $this->log_queries = $debug;
 335          }
 336  
 337          if( ! extension_loaded('mysql') )
 338          { // The mysql extension is not loaded, try to dynamically load it:
 339              $mysql_ext_file = is_windows() ? 'php_mysql.dll' : 'mysql.so';
 340              @dl( $mysql_ext_file );
 341  
 342              if( ! extension_loaded('mysql') )
 343              { // Still not loaded:
 344                  $this->print_error( 'The PHP MySQL module could not be loaded.', '
 345                      <p>You must edit your php configuration (php.ini) and enable this module ('.$mysql_ext_file.').</p>
 346                      <p>Do not forget to restart your webserver (if necessary) after editing the PHP conf.</p>', false );
 347                  return;
 348              }
 349          }
 350  
 351          $new_link = isset( $params['new_link'] ) ? $params['new_link'] : false;
 352          $client_flags = isset( $params['client_flags'] ) ? $params['client_flags'] : 0;
 353  
 354          if( ! isset($params['handle']) )
 355          { // Connect to the Database:
 356              // echo "mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags )";

 357              $this->dbhandle = @mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags );
 358          }
 359  
 360          if( ! $this->dbhandle )
 361          {
 362              $mysql_error = mysql_error();
 363              if( empty($mysql_error) )
 364              { // there was a PHP error, like with version below 4.3 which do not support new_link and client_flags; let PHP throw an error:
 365                  $this->print_error( 'Error establishing a database connection!', '
 366                      <p>If you are running a PHP version below 4.3, please upgrade.</p>', false );    // fp> Other causes include: simple tests passing wrong params!

 367  
 368                  // Let PHP throw an error:

 369                  mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags );
 370              }
 371              else
 372              {
 373                  $this->print_error( 'Error establishing a database connection!', '
 374                      <p>('.$mysql_error.')</p>
 375                      <ol>
 376                          <li>Are you sure you have typed the correct user/password?</li>
 377                          <li>Are you sure that you have typed the correct hostname?</li>
 378                          <li>Are you sure that the database server is running?</li>
 379                      </ol>', false );
 380              }
 381          }
 382          elseif( isset($this->dbname) )
 383          {
 384              $this->select($this->dbname);
 385          }
 386  
 387  
 388          if( !empty($params['connection_charset']) )
 389          {    // Specify which charset we are using on the client:
 390              $this->set_connection_charset($params['connection_charset']);
 391          }
 392  
 393          /*

 394          echo '<br />Server: '.$this->get_var( 'SELECT @@character_set_server' );

 395          echo '<br />Database: '.$this->get_var( 'SELECT @@character_set_database' );

 396          echo '<br />Connection: '.$this->get_var( 'SELECT @@character_set_connection' );

 397          echo '<br />Client: '.$this->get_var( 'SELECT @@character_set_client' );

 398          echo '<br />Results: '.$this->get_var( 'SELECT @@character_set_results' );

 399          */
 400  
 401  
 402          if( isset($params['aliases']) )
 403          { // Prepare aliases for replacements:
 404              foreach( $params['aliases'] as $dbalias => $dbreplace )
 405              {
 406                  $this->dbaliases[] = '#\b'.$dbalias.'\b#'; // \b = word boundary

 407                  $this->dbreplaces[] = $dbreplace;
 408                  // echo '<br />'.'#\b'.$dbalias.'\b#';

 409              }
 410              // echo count($this->dbaliases);

 411          }
 412  
 413          if( $debug )
 414          { // Force MySQL strict mode
 415              $this->query( 'SET sql_mode = "TRADITIONAL"' );
 416          }
 417      }
 418  
 419  
 420      /**

 421       * Select a DB (if another one needs to be selected)

 422       */
 423  	function select($db)
 424      {
 425          if( !@mysql_select_db($db, $this->dbhandle) )
 426          {
 427              $this->print_error( 'Error selecting database ['.$db.']!', '
 428                  <ol>
 429                      <li>Are you sure the database exists?</li>
 430                      <li>Are you sure the DB user is allowed to use that database?</li>
 431                      <li>Are you sure there is a valid database connection?</li>
 432                  </ol>', false );
 433          }
 434      }
 435  
 436  
 437      /**

 438       * Format a string correctly for safe insert under all PHP conditions

 439       */
 440  	function escape($str)
 441      {
 442          return mysql_real_escape_string($str, $this->dbhandle);
 443      }
 444  
 445  
 446      /**

 447       * Quote a value, either in single quotes (and escaped) or if it's NULL as 'NULL'.

 448       *

 449       * @return string Quoted (and escaped) value or 'NULL'.

 450       */
 451  	function quote($str)
 452      {
 453          if( is_null( $str ) )
 454          {
 455              return 'NULL';
 456          }
 457          elseif( is_array( $str ) )
 458          {
 459              $r = '';
 460              foreach( $str as $elt )
 461              {
 462                  $r .= $this->quote($elt).',';
 463              }
 464              $r = substr( $r, 0, strlen( $r ) - 1 );
 465              return $r;
 466          }
 467          else
 468          {
 469              return "'".mysql_real_escape_string($str, $this->dbhandle)."'";
 470          }
 471      }
 472  
 473  
 474      /**

 475       * @return string Return the given value or 'NULL', if it's === NULL.

 476       */
 477  	function null($val)
 478      {
 479          if( $val === NULL )
 480              return 'NULL';
 481          else
 482              return $val;
 483      }
 484  
 485  
 486      /**

 487       * Returns the correct WEEK() function to get the week number for the given date.

 488       *

 489       * @link http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html

 490       *

 491       * @todo disable when MySQL < 4

 492       * @param string will be used as is

 493       * @param integer 0 for sunday, 1 for monday

 494       */
 495  	function week( $date, $startofweek )
 496      {
 497          if( $startofweek == 1 )
 498          { // Week starts on Monday, week 1 must have a monday in this year:
 499              return ' WEEK( '.$date.', 5 ) ';
 500          }
 501  
 502          // Week starts on Sunday, week 1 must have a sunday in this year:

 503          return ' WEEK( '.$date.', 0 ) ';
 504      }
 505  
 506  
 507      /**

 508       * Print SQL/DB error.

 509       *

 510       * TODO: fp> bloated: it probably doesn't make sense to display errors if we don't stop. Any use case?

 511       *       dh> Sure. Local testing (and test cases).

 512       *

 513       * @param string Short error (no HTML)

 514       * @param string Extended description/help for the error (for HTML)

 515       * @param string|false Query title; false if {@link DB::$last_query} should not get displayed

 516       */
 517  	function print_error( $title = '', $html_str = '', $query_title = '' )
 518      {
 519          // All errors go to the global error array $EZSQL_ERROR..

 520          global $EZSQL_ERROR, $is_cli;
 521  
 522          $this->error = true;
 523  
 524          // If no special error string then use mysql default..

 525          $this->last_error = empty($title) ? ( mysql_error($this->dbhandle).'(Errno='.mysql_errno($this->dbhandle).')' ) : $title;
 526  
 527          // Log this error to the global array..

 528          $EZSQL_ERROR[] = array(
 529              'query' => $this->last_query,
 530              'error_str'  => $this->last_error
 531          );
 532  
 533          if( ! ( $this->halt_on_error || $this->show_errors ) )
 534          { // no reason to generate a nice message:
 535              return;
 536          }
 537  
 538          if( $is_cli )
 539          { // Clean error message for command line interface:
 540              $err_msg = "MySQL error! {$this->last_error}\n";
 541              if( ! empty($this->last_query) && $query_title !== false )
 542              {
 543                  $err_msg .= "Your query: $query_title\n";
 544                  $err_msg .= $this->format_query( $this->last_query, false );
 545              }
 546          }
 547          else
 548          {
 549              $err_msg = '<p class="error">MySQL error!</p>'."\n";
 550              $err_msg .= "<div><p><strong>{$this->last_error}</strong></p>\n";
 551              $err_msg .= $html_str;
 552              if( !empty($this->last_query) && $query_title !== false )
 553              {
 554                  $err_msg .= '<p class="error">Your query: '.$query_title.'</p>';
 555                  $err_msg .= '<pre>';
 556                  $err_msg .= $this->format_query( $this->last_query, ! $is_cli );
 557                  $err_msg .= '</pre>';
 558              }
 559              $err_msg .= "</div>\n";
 560          }
 561  
 562          if( $this->halt_on_error )
 563          {
 564              if( function_exists('debug_die') )
 565              {
 566                  debug_die( $err_msg );
 567              }
 568              else
 569              {
 570                  die( $err_msg );
 571              }
 572          }
 573          elseif( $this->show_errors )
 574          { // If there is an error then take note of it
 575              echo '<div class="error">';
 576              echo $err_msg;
 577              echo '</div>';
 578          }
 579  
 580      }
 581  
 582  
 583      /**

 584       * Kill cached query results

 585       */
 586  	function flush()
 587      {
 588          // Get rid of these

 589          $this->last_result = NULL;
 590          $this->last_query = NULL;
 591      }
 592  
 593  
 594    /**

 595       * Get MYSQL version

 596       */
 597  	function get_version()
 598      {
 599          if( isset( $this->version ) )
 600          {
 601              return $this->version;
 602          }
 603  
 604      $save_show_errors = $this->show_errors;
 605          $save_halt_on_error = $this->halt_on_error;
 606          // Blatantly ignore any error generated by potentially unknown function...

 607          $this->show_errors = false;
 608          $this->halt_on_error = false;
 609          $last_error = $this->last_error;
 610          $error = $this->error;
 611          if( ($this->version_long = $this->get_var( 'SELECT VERSION()' ) ) === NULL )
 612          {    // Very old version ( < 4.0 )
 613              $this->version = '';
 614              $this->version_long = '';
 615          }
 616          else
 617          {
 618              $this->version = preg_replace( '¤-.*¤', '', $this->version_long );
 619          }
 620          $this->show_errors = $save_show_errors;
 621          $this->halt_on_error = $save_halt_on_error;
 622          $this->last_error = $last_error;
 623          $this->error = $error;
 624          $this->halt_on_error = false;
 625  
 626          return $this->version;
 627      }
 628  
 629      /**

 630       * Basic Query

 631       *

 632       * @param string SQL query

 633       * @param string title for debugging

 634       * @return mixed # of rows affected or false if error

 635       */
 636  	function query( $query, $title = '' )
 637      {
 638          global $Timer;
 639  
 640          // initialise return

 641          $return_val = 0;
 642  
 643          // Flush cached values..

 644          $this->flush();
 645  
 646          // Log how the function was called

 647          $this->func_call = '$db->query("'.$query.'")';
 648          // echo $this->func_call, '<br />';

 649  
 650          // Replace aliases:

 651          if( ! empty($this->dbaliases) )
 652          {
 653              // TODO: this should only replace the table name part(s), not the whole query!

 654              // blueyed> I've changed it to replace in table name parts for UPDATE, INSERT and REPLACE, because

 655              //          it corrupted serialized data..

 656              //          IMHO, a cleaner solution would be to use {T_xxx} in the queries and replace it here. In object properties (e.g. DataObject::$dbtablename), only "T_xxx" would get used and surrounded by "{..}" in the queries it creates.

 657  
 658              if( preg_match( '~^\s*(UPDATE\s+)(.*?)(\sSET\s.*)$~is', $query, $match ) )
 659              { // replace only between UPDATE and SET:
 660                  $query = $match[1].preg_replace( $this->dbaliases, $this->dbreplaces, $match[2] ).$match[3];
 661              }
 662              elseif( preg_match( '~^\s*(INSERT|REPLACE\s+)(.*?)(\s(VALUES|SET)\s.*)$~is', $query, $match ) )
 663              { // replace only between INSERT|REPLACE and VALUES|SET:
 664                  $query = $match[1].preg_replace( $this->dbaliases, $this->dbreplaces, $match[2] ).$match[3];
 665              }
 666              else
 667              { // replace in whole query:
 668                  $query = preg_replace( $this->dbaliases, $this->dbreplaces, $query );
 669  
 670                  if( ! empty($this->table_options) && preg_match( '#^ \s* create \s* table \s #ix', $query) )
 671                  { // Query is a table creation, we add table options:
 672                      $query = preg_replace( '~;\s*$~', '', $query ); // remove any ";" at the end

 673                      $query .= ' '.$this->table_options;
 674                  }
 675              }
 676          }
 677          elseif( ! empty($this->table_options) )
 678          { // No aliases, but table_options:
 679              if( preg_match( '#^ \s* create \s* table \s #ix', $query) )
 680              { // Query is a table creation, we add table options:
 681                  $query .= $this->table_options;
 682              }
 683          }
 684          // echo '<p>'.$query.'</p>';

 685  
 686          // Keep track of the last query for debug..

 687          $this->last_query = $query;
 688  
 689          // Perform the query via std mysql_query function..

 690          $this->num_queries++;
 691  
 692          if( $this->log_queries )
 693          {    // We want to log queries:
 694              $this->queries[ $this->num_queries - 1 ] = array(
 695                  'title' => $title,
 696                  'sql' => $query,
 697                  'rows' => -1,
 698                  'time' => 'unknown',
 699                  'results' => 'unknown' );
 700          }
 701  
 702          if( is_object($Timer) )
 703          {
 704              // Resume global query timer

 705              $Timer->resume( 'sql_queries' );
 706              // Start a timer for this particular query:

 707              $Timer->start( 'sql_query', false );
 708  
 709              // Run query:

 710              $this->result = @mysql_query( $query, $this->dbhandle );
 711  
 712              if( $this->log_queries )
 713              {    // We want to log queries:
 714                  // Get duration for last query:

 715                  $this->queries[ $this->num_queries - 1 ]['time'] = $Timer->get_duration( 'sql_query', 10 );
 716              }
 717  
 718              // Pause global query timer:

 719              $Timer->pause( 'sql_queries' );
 720          }
 721          else
 722          {
 723              // Run query:

 724              $this->result = @mysql_query( $query, $this->dbhandle );
 725          }
 726  
 727          // If there is an error then take note of it..

 728          if( mysql_error($this->dbhandle) )
 729          {
 730              @mysql_free_result($this->result);
 731              $this->print_error( '', '', $title );
 732              return false;
 733          }
 734  
 735          if( preg_match( '#^\s*(INSERT|DELETE|UPDATE|REPLACE)\s#i', $query, $match ) )
 736          { // Query was an insert, delete, update, replace:
 737  
 738              $this->rows_affected = mysql_affected_rows($this->dbhandle);
 739              if( $this->log_queries )
 740              {    // We want to log queries:
 741                  $this->queries[ $this->num_queries - 1 ]['rows'] = $this->rows_affected;
 742              }
 743  
 744              // Take note of the insert_id, for INSERT and REPLACE:

 745              $match[1] = strtoupper($match[1]);
 746              if( $match[1] == 'INSERT' || $match[1] == 'REPLACE' )
 747              {
 748                  $this->insert_id = mysql_insert_id($this->dbhandle);
 749              }
 750  
 751              // Return number of rows affected

 752              $return_val = $this->rows_affected;
 753          }
 754          else
 755          { // Query was a select, alter, etc...:
 756              $this->num_rows = 0;
 757  
 758              if( is_resource($this->result) )
 759              { // It's not a resource for CREATE or DROP for example and can even trigger a fatal error (see http://forums.b2evolution.net//viewtopic.php?t=9529)
 760  
 761                  // Store Query Results

 762                  while( $row = mysql_fetch_object($this->result) )
 763                  {
 764                      // Store relults as an objects within main array

 765                      $this->last_result[$this->num_rows] = $row;
 766                      $this->num_rows++;
 767                  }
 768              }
 769  
 770              if( $this->log_queries )
 771              {    // We want to log queries:
 772                  $this->queries[ $this->num_queries - 1 ]['rows'] = $this->num_rows;
 773              }
 774  
 775              // Return number of rows selected

 776              $return_val = $this->num_rows;
 777          }
 778  
 779          if( $this->log_queries )
 780          {    // We want to log queries:
 781              if( $this->debug_dump_function_trace_for_queries )
 782              {
 783                  $this->queries[ $this->num_queries - 1 ]['function_trace'] = debug_get_backtrace( $this->debug_dump_function_trace_for_queries, array( array( 'class' => 'DB' ) ), 1 ); // including first stack entry from class DB

 784              }
 785  
 786              if( $this->debug_dump_rows )
 787              {
 788                  $this->queries[ $this->num_queries - 1 ]['results'] = $this->debug_get_rows_table( $this->debug_dump_rows );
 789              }
 790          }
 791  
 792          // Free original query's result:

 793          @mysql_free_result($this->result);
 794  
 795          // EXPLAIN JOINS ??

 796          if( $this->log_queries && $this->debug_explain_joins && preg_match( '#^ \s* SELECT \s #ix', $query) )
 797          { // Query was a select, let's try to explain joins...
 798  
 799              // save values:

 800              $saved_last_result = $this->last_result;
 801              $saved_num_rows = $this->num_rows;
 802  
 803              $this->last_result = NULL;
 804              $this->num_rows = 0;
 805  
 806              $this->result = @mysql_query( 'EXPLAIN '.$query, $this->dbhandle );
 807  
 808              // Store Query Results

 809              $this->num_rows = 0;
 810              while( $row = @mysql_fetch_object($this->result) )
 811              {
 812                  // Store results as an objects within main array

 813                  $this->last_result[$this->num_rows] = $row;
 814                  $this->num_rows++;
 815              }
 816  
 817              $this->queries[ $this->num_queries - 1 ]['explain'] = $this->debug_get_rows_table( 100, true );
 818  
 819              // Free "EXPLAIN" result resource:

 820              @mysql_free_result($this->result);
 821  
 822              // Restore:

 823              $this->last_result = $saved_last_result;
 824              $this->num_rows = $saved_num_rows;
 825          }
 826  
 827          return $return_val;
 828      }
 829  
 830  
 831      /**

 832       * Get one variable from the DB - see docs for more detail

 833       *

 834       * Note: To be sure that you received NULL from the DB and not "no rows" check

 835       *       for {@link $num_rows}.

 836       *

 837       * @return mixed NULL if not found, the value otherwise (which may also be NULL).

 838       */
 839  	function get_var( $query = NULL, $x = 0, $y = 0, $title = '' )
 840      {
 841          // Log how the function was called

 842          $this->func_call = "\$db->get_var(\"$query\",$x,$y)";
 843  
 844          // If there is a query then perform it if not then use cached results..

 845          if( $query )
 846          {
 847              $this->query($query, $title);
 848          }
 849  
 850          // Extract var out of cached results based x,y vals

 851          if( $this->last_result[$y] )
 852          {
 853              $values = array_values(get_object_vars($this->last_result[$y]));
 854          }
 855  
 856          if( isset($values[$x]) )
 857          {
 858              return $values[$x];
 859          }
 860  
 861          return NULL;
 862      }
 863  
 864  
 865      /**

 866       * Get one row from the DB - see docs for more detail

 867       *

 868       * @return array|object

 869       */
 870  	function get_row( $query = NULL, $output = OBJECT, $y = 0, $title = '' )
 871      {
 872          // If there is a query then perform it if not then use cached results..

 873          if( $query )
 874          {
 875              $this->query($query, $title);
 876          }
 877  
 878          // If the output is an object then return object using the row offset..

 879          if( $output == OBJECT )
 880          {
 881              return $this->last_result[$y]
 882                  ? $this->last_result[$y]
 883                  : NULL;
 884          }
 885          // If the output is an associative array then return row as such..

 886          elseif( $output == ARRAY_A )
 887          {
 888              return $this->last_result[$y]
 889                  ? get_object_vars( $this->last_result[$y] )
 890                  : array();
 891          }
 892          // If the output is an numerical array then return row as such..

 893          elseif( $output == ARRAY_N )
 894          {
 895              return $this->last_result[$y]
 896                  ? array_values( get_object_vars($this->last_result[$y]) )
 897                  : array();
 898          }
 899          // If invalid output type was specified..

 900          else
 901          {
 902              $this->print_error('DB::get_row(string query, output type, int offset) -- Output type must be one of: OBJECT, ARRAY_A, ARRAY_N', '', false);
 903          }
 904      }
 905  
 906  
 907      /**

 908       * Function to get 1 column from the cached result set based in X index

 909       * see docs for usage and info

 910       *

 911       * @return array

 912       */
 913  	function get_col( $query = NULL, $x = 0, $title = '' )
 914      {
 915          // If there is a query then perform it if not then use cached results..

 916          if( $query )
 917          {
 918              $this->query( $query, $title );
 919          }
 920  
 921          // Extract the column values

 922          $new_array = array();
 923          for( $i = 0, $count = count($this->last_result); $i < $count; $i++ )
 924          {
 925              $new_array[$i] = $this->get_var( NULL, $x, $i );
 926          }
 927  
 928          return $new_array;
 929      }
 930  
 931  
 932      /**

 933       * Function to get the second column from the cached result indexed by the first column

 934       *

 935       * @return array [col_0] => col_1

 936       */
 937  	function get_assoc( $query = NULL, $title = '' )
 938      {
 939          // If there is a query then perform it if not then use cached results..

 940          if( $query )
 941          {
 942              $this->query( $query, $title );
 943          }
 944  
 945          // Extract the column values

 946          $new_array = array();
 947          for( $i = 0, $count = count($this->last_result); $i < $count; $i++ )
 948          {
 949              $key = $this->get_var( NULL, 0, $i );
 950  
 951              $new_array[$key] = $this->get_var( NULL, 1, $i );
 952          }
 953  
 954          return $new_array;
 955      }
 956  
 957  
 958      /**

 959       * Return the the query as a result set - see docs for more details

 960       *

 961       * @return array

 962       */
 963  	function get_results( $query = NULL, $output = OBJECT, $title = '' )
 964      {
 965          // If there is a query then perform it if not then use cached results..

 966          if( $query )
 967          {
 968              $this->query($query, $title);
 969          }
 970  
 971          // Send back array of objects. Each row is an object

 972          if( $output == OBJECT )
 973          {
 974              return $this->last_result ? $this->last_result : array();
 975          }
 976          elseif( $output == ARRAY_A || $output == ARRAY_N )
 977          {
 978              $new_array = array();
 979  
 980              if( $this->last_result )
 981              {
 982                  $i = 0;
 983  
 984                  foreach( $this->last_result as $row )
 985                  {
 986                      $new_array[$i] = get_object_vars($row);
 987  
 988                      if( $output == ARRAY_N )
 989                      {
 990                          $new_array[$i] = array_values($new_array[$i]);
 991                      }
 992  
 993                      $i++;
 994                  }
 995  
 996                  return $new_array;
 997              }
 998              else
 999              {
1000                  return array();
1001              }
1002          }
1003      }
1004  
1005  
1006      /**

1007       * Get a table (or "<p>No Results.</p>") for the SELECT query results.

1008       *

1009       * @return string HTML table or "No Results" if the

1010       */
1011  	function debug_get_rows_table( $max_lines, $break_at_comma = false )
1012      {
1013          $r = '';
1014  
1015          if( ! is_resource($this->result) )
1016          {
1017              return '<p>No Results.</p>';
1018          }
1019  
1020          // Get column info:

1021          $col_info = array();
1022          $n = mysql_num_fields($this->result);
1023          $i = 0;
1024          while( $i < $n )
1025          {
1026              $col_info[$i] = mysql_fetch_field($this->result, $i);
1027              $i++;
1028          }
1029  
1030          // =====================================================

1031          // Results top rows

1032          $r .= '<table cellspacing="0" summary="Results for query"><tr>';
1033          for( $i = 0, $count = count($col_info); $i < $count; $i++ )
1034          {
1035              $r .= '<th><span class="type">'.$col_info[$i]->type.' '.$col_info[$i]->max_length.'</span><br />'
1036                          .$col_info[$i]->name.'</th>';
1037          }
1038          $r .= '</tr>';
1039  
1040          $i=0;
1041  
1042          // ======================================================

1043          // print main results

1044          if( $this->last_result )
1045          {
1046              foreach( $this->get_results(NULL,ARRAY_N) as $one_row )
1047              {
1048                  $i++;
1049                  if( $i >= $max_lines )
1050                  {
1051                      break;
1052                  }
1053                  $r .= '<tr>';
1054                  foreach( $one_row as $item )
1055                  {
1056                      if( $i % 2 )
1057                      {
1058                          $r .= '<td class="odd">';
1059                      }
1060                      else
1061                      {
1062                          $r .= '<td>';
1063                      }
1064  
1065                      if( $break_at_comma )
1066                      {
1067                          $item = str_replace( ',', '<br />', $item );
1068                          $item = str_replace( ';', '<br />', $item );
1069                          $r .= $item;
1070                      }
1071                      else
1072                      {
1073                          if( strlen( $item ) > 50 )
1074                          {
1075                              $item = substr( $item, 0, 50 ).'...';
1076                          }
1077                          $r .= htmlspecialchars($item);
1078                      }
1079                      $r .= '</td>';
1080                  }
1081  
1082                  $r .= '</tr>';
1083              }
1084  
1085          } // if last result

1086          else
1087          {
1088              $r .= '<tr><td colspan="'.(count($col_info)+1).'">No Results</td></tr>';
1089          }
1090          if( $i >= $max_lines )
1091          {
1092              $r .= '<tr><td colspan="'.(count($col_info)+1).'">Max number of dumped rows has been reached.</td></tr>';
1093          }
1094  
1095          $r .= '</table>';
1096  
1097          return $r;
1098      }
1099  
1100  
1101      /**

1102       * Format a SQL query

1103       * @static

1104       * @todo dh> Steal the code from phpMyAdmin :)

1105       * @param string SQL

1106       * @param boolean Format with/for HTML?

1107       */
1108  	function format_query( $sql, $html = true )
1109      {
1110          $sql = str_replace("\t", '  ', $sql );
1111          if( $html )
1112          {
1113              $sql = htmlspecialchars( $sql );
1114              $replace_prefix = "<br />\n";
1115          }
1116          else
1117          {
1118              $replace_prefix = "\n";
1119          }
1120  
1121          $search = array(
1122              '~(FROM|WHERE|GROUP BY|ORDER BY|LIMIT|VALUES)~',
1123              '~(AND |OR )~',
1124              );
1125          $replace = array(
1126                  $replace_prefix.'$1',
1127                  $replace_prefix.'&nbsp; $1',
1128              );
1129          $sql = preg_replace( $search, $replace, $sql );
1130  
1131          return $sql;
1132      }
1133  
1134  
1135      /**

1136       * Displays all queries that have been executed

1137       */
1138  	function dump_queries()
1139      {
1140          global $Timer;
1141          if( is_object( $Timer ) )
1142          {
1143              $time_queries = $Timer->get_duration( 'sql_queries' );
1144          }
1145          else
1146          {
1147              $time_queries = 0;
1148          }
1149  
1150          $count_queries = 0;
1151          $count_rows = 0;
1152  
1153          echo '<strong>DB queries:</strong> '.$this->num_queries."<br />\n";
1154  
1155          if( ! $this->log_queries )
1156          { // nothing more to do here..
1157              return;
1158          }
1159  
1160          foreach( $this->queries as $query )
1161          {
1162              $count_queries++;
1163              echo '<h4>Query #'.$count_queries.': '.$query['title']."</h4>\n";
1164              echo '<code>';
1165              echo $this->format_query( $query['sql'] );
1166              echo "</code>\n";
1167  
1168              // Color-Format duration: long => red, fast => green, normal => black

1169              if( $query['time'] > $this->query_duration_slow )
1170              {
1171                  $style_time_text = 'color:red;font-weight:bold;';
1172                  $style_time_graph = 'background-color:red;';
1173              }
1174              elseif( $query['time'] < $this->query_duration_fast )
1175              {
1176                  $style_time_text = 'color:green;';
1177                  $style_time_graph = 'background-color:green;';
1178              }
1179              else
1180              {
1181                  $style_time_text = '';
1182                  $style_time_graph = 'background-color:black;';
1183              }
1184  
1185              // Number of rows with time (percentage and graph, if total time available)

1186              echo '<div class="query_info">';
1187              echo 'Rows: '.$query['rows'];
1188  
1189              echo ' &ndash; Time: ';
1190              if( $style_time_text )
1191              {
1192                  echo '<span style="'.$style_time_text.'">';
1193              }
1194              echo number_format( $query['time'], 4 ).'s';
1195  
1196              if( $time_queries > 0 )
1197              { // We have a total time we can use to calculate percentage:
1198                  echo ' ('.number_format( 100/$time_queries * $query['time'], 2 ).'%)';
1199              }
1200  
1201              if( $style_time_text )
1202              {
1203                  echo '</span>';
1204              }
1205  
1206              if( $time_queries > 0 )
1207              { // We have a total time we can use to display a graph/bar:
1208                  echo '<div style="margin:0; padding:0; height:12px; width:'.( round( 100/$time_queries * $query['time'] ) ).'%;'.$style_time_graph.'"></div>';
1209              }
1210              echo '</div>';
1211  
1212  
1213              // Explain:

1214              if( isset($query['explain']) )
1215              {
1216                  echo $query['explain'];
1217              }
1218  
1219              // Results:

1220              if( $query['results'] != 'unknown' )
1221              {
1222                  echo $query['results'];
1223              }
1224  
1225              // Function trace:

1226              if( isset($query['function_trace']) )
1227              {
1228                  echo $query['function_trace'];
1229              }
1230  
1231              $count_rows += $query['rows'];
1232          }
1233          echo "\n<strong>Total rows:</strong> $count_rows<br />\n";
1234      }
1235  
1236  
1237      /**

1238       * BEGIN A TRANSCATION

1239       *

1240       * Note:  By default, MySQL runs with autocommit mode enabled.

1241       * This means that as soon as you execute a statement that updates (modifies)

1242       * a table, MySQL stores the update on disk.

1243       * Once you execute a BEGIN, the updates are "pending" until you execute a

1244       * {@link DB::commit() COMMIT} or a {@link DB:rollback() ROLLBACK}

1245       *

1246       * Note 2: standard syntax would be START TRANSACTION but it's not supported by older

1247       * MySQL versions whereas BEGIN is...

1248       *

1249       * Note 3: The default isolation level is REPEATABLE READ.

1250       */
1251  	function begin()
1252      {
1253          if( $this->use_transactions )
1254          {
1255              $this->query( 'BEGIN', 'BEGIN transaction' );
1256  
1257              $this->transaction_nesting_level++;
1258          }
1259      }
1260  
1261  
1262      /**

1263       * Commit current transaction

1264       */
1265  	function commit()
1266      {
1267          if( $this->use_transactions )
1268          {
1269              if( $this->transaction_nesting_level == 1 )
1270              { // Only COMMIT if there are no remaining nested transactions:
1271                  if( $this->rollback_nested_transaction )
1272                  {
1273                      $this->query( 'ROLLBACK', 'ROLLBACK transaction because there was a failure somewhere in the nesting of transactions' );
1274                  }
1275                  else
1276                  {
1277                      $this->query( 'COMMIT', 'COMMIT transaction' );
1278                  }
1279                  $this->rollback_nested_transaction = false;
1280              }
1281              if( $this->transaction_nesting_level )
1282              {
1283                  $this->transaction_nesting_level--;
1284              }
1285          }
1286      }
1287  
1288  
1289      /**

1290       * Rollback current transaction

1291       */
1292  	function rollback()
1293      {
1294          if( $this->use_transactions )
1295          {
1296              if( $this->transaction_nesting_level == 1 )
1297              { // Only ROLLBACK if there are no remaining nested transactions:
1298                  $this->query( 'ROLLBACK', 'ROLLBACK transaction' );
1299                  $this->rollback_nested_transaction = false;
1300              }
1301              else
1302              { // Remember we'll have to roll back at the end!
1303                  $this->rollback_nested_transaction = true;
1304              }
1305              if( $this->transaction_nesting_level )
1306              {
1307                  $this->transaction_nesting_level--;
1308              }
1309          }
1310      }
1311  
1312  
1313      /**

1314       * Set the charset of the connection.

1315       *

1316       * WARNING: this will fail on MySQL 3.23

1317       *

1318       * @staticvar array "regular charset => mysql charset map"

1319       * @param string Charset

1320       * @param boolean Use the "regular charset => mysql charset map"?

1321       * @return boolean true on success, false on failure

1322       */
1323  	function set_connection_charset( $charset, $use_map = false )
1324      {
1325          global $Debuglog;
1326  
1327          /**

1328           * This is taken from phpMyAdmin (libraries/select_lang.lib.php).

1329           */
1330          static $mysql_charset_map = array(
1331                  'big5'         => 'big5',
1332                  'cp-866'       => 'cp866',
1333                  'euc-jp'       => 'ujis',
1334                  'euc-kr'       => 'euckr',
1335                  'gb2312'       => 'gb2312',
1336                  'gbk'          => 'gbk',
1337                  'iso-8859-1'   => 'latin1',
1338                  'iso-8859-2'   => 'latin2',
1339                  'iso-8859-7'   => 'greek',
1340                  'iso-8859-8'   => 'hebrew',
1341                  'iso-8859-8-i' => 'hebrew',
1342                  'iso-8859-9'   => 'latin5',
1343                  'iso-8859-13'  => 'latin7',
1344                  'iso-8859-15'  => 'latin1',
1345                  'koi8-r'       => 'koi8r',
1346                  'shift_jis'    => 'sjis',
1347                  'tis-620'      => 'tis620',
1348                  'utf-8'        => 'utf8',
1349                  'windows-1250' => 'cp1250',
1350                  'windows-1251' => 'cp1251',
1351                  'windows-1252' => 'latin1',
1352                  'windows-1256' => 'cp1256',
1353                  'windows-1257' => 'cp1257',
1354              );
1355  
1356          $charset = strtolower($charset);
1357  
1358          if( $use_map )
1359          {
1360              if( ! isset($mysql_charset_map[$charset]) )
1361              {
1362                  return false;
1363              }
1364  
1365              $charset = $mysql_charset_map[$charset];
1366          }
1367  
1368          $r = true;
1369          if( $charset != $this->connection_charset )
1370          {
1371              // SET NAMES is not supported by MySQL 3.23 and for a non-supported charset even not in MySQL 5 probably..

1372  
1373              $save_show_errors = $this->show_errors;
1374              $save_halt_on_error = $this->halt_on_error;
1375              $this->show_errors = false;
1376              $this->halt_on_error = false;
1377              $last_error = $this->last_error;
1378              $error = $this->error;
1379              if( $this->query( 'SET NAMES '.$charset ) === false )
1380              {
1381                  $Debuglog->add( 'Could not "SET NAMES '.$charset.'"! (MySQL error: '.strip_tags($this->last_error).')', 'locale' );
1382  
1383                  $r = false;
1384              }
1385              else
1386              {
1387                  $Debuglog->add( 'Set DB connection charset: '.$charset, 'locale' );
1388              }
1389              $this->show_errors = $save_show_errors;
1390              $this->halt_on_error = $save_halt_on_error;
1391              // Blatantly ignore any error generated by SET NAMES...

1392              $this->last_error = $last_error;
1393              $this->error = $error;
1394  
1395              // dh> TODO: this should only get set in case of success, I'd say..

1396              $this->connection_charset = $charset;
1397          }
1398  
1399          return $r;
1400      }
1401  
1402  }
1403  
1404  
1405  /*

1406   * $Log: _db.class.php,v $

1407   * Revision 1.2  2007/10/01 19:02:23  fplanque

1408   * MySQL version check

1409   *

1410   * Revision 1.1  2007/06/25 10:58:58  fplanque

1411   * MODULES (refactored MVC)

1412   *

1413   * Revision 1.61  2007/06/19 23:17:52  blueyed

1414   * Force MySQL strict mode, if $debug

1415   *

1416   * Revision 1.60  2007/06/19 23:15:08  blueyed

1417   * doc fixes

1418   *

1419   * Revision 1.59  2007/05/14 02:44:14  fplanque

1420   * allow quoting of arrays

1421   *

1422   * Revision 1.58  2007/04/26 00:11:07  fplanque

1423   * (c) 2007

1424   *

1425   * Revision 1.57  2007/03/11 22:30:08  fplanque

1426   * cleaned up group perms

1427   *

1428   * Revision 1.56  2007/02/09 17:28:56  blueyed

1429   * doc

1430   *

1431   * Revision 1.55  2007/01/29 01:21:22  blueyed

1432   * Do not let $transaction_nesting_level become negative!

1433   *

1434   * Revision 1.54  2007/01/25 05:14:13  fplanque

1435   * rollback

1436   *

1437   * Revision 1.52  2006/12/14 00:42:04  fplanque

1438   * A little bit of windows detection / normalization

1439   *

1440   * Revision 1.51  2006/12/07 23:12:21  fplanque

1441   * @var needs to have only one argument: the variable type

1442   * Otherwise, I can't code!

1443   *

1444   * Revision 1.50  2006/12/03 21:27:21  blueyed

1445   * Save and reset $error with set_connection_charset(); TODO

1446   *

1447   * Revision 1.49  2006/11/28 02:52:26  fplanque

1448   * doc

1449   *

1450   * Revision 1.48  2006/11/28 00:33:01  blueyed

1451   * Removed DB::compString() (never used) and DB::get_list() (just a macro and better to have in the 4 used places directly; Cleanup/normalization; no extended regexp, when not needed!

1452   *

1453   * Revision 1.47  2006/11/27 20:54:07  fplanque

1454   * doc

1455   *

1456   * Revision 1.46  2006/11/27 01:35:47  blueyed

1457   * Removed get_col_info() and free mysql_result in query() always again

1458   *

1459   * Revision 1.45  2006/11/26 11:12:38  fplanque

1460   * doc / todo

1461   *

1462   * Revision 1.44  2006/11/26 03:17:53  blueyed

1463   * doc about resource freeing and flush() in general

1464   *

1465   * Revision 1.43  2006/11/26 02:30:39  fplanque

1466   * doc / todo

1467   *

1468   * Revision 1.42  2006/11/24 18:27:27  blueyed

1469   * Fixed link to b2evo CVS browsing interface in file docblocks

1470   *

1471   * Revision 1.41  2006/11/23 15:33:58  blueyed

1472   * Small opt

1473   *

1474   * Revision 1.40  2006/11/20 12:23:28  blueyed

1475   * Optimized col_info handling: obsoleted DB::col_info: use DB::get_col_info() instead (lazy-loading of column info)

1476   *

1477   * Revision 1.39  2006/11/19 23:30:38  fplanque

1478   * made simpletest almost installable by almost bozos almost like me

1479   *

1480   * Revision 1.38  2006/11/18 03:44:48  fplanque

1481   * reverted to optimized col info

1482   *

1483   * Revision 1.36  2006/11/17 01:44:38  fplanque

1484   * A function should NEVER FAIL SILENTLY!

1485   *

1486   * Revision 1.35  2006/11/14 17:35:39  blueyed

1487   * small opt

1488   *

1489   * Revision 1.34  2006/11/04 18:39:15  blueyed

1490   * Normalized

1491   *

1492   * Revision 1.33  2006/11/04 18:11:42  fplanque

1493   * comments

1494   *

1495   * Revision 1.32  2006/11/04 01:29:55  blueyed

1496   * Better error displaying. Fix: use $html_str in print_error()

1497   *

1498   * Revision 1.31  2006/11/04 01:22:29  blueyed

1499   * Proposed fix for users with PHP < 4.3: let them get the PHP error.

1500   *

1501   * Revision 1.30  2006/11/03 00:22:21  blueyed

1502   * $log_queries follows $debug global; Removed dumpvar() and vardump() - use pre_dump()

1503   *

1504   * Revision 1.29  2006/11/02 19:49:22  fplanque

1505   * no message

1506   *

1507   * Revision 1.28  2006/10/28 15:05:25  blueyed

1508   * CLI/non-HTML support for print_error() and format_query()

1509   *

1510   * Revision 1.27  2006/10/14 03:05:59  blueyed

1511   * MFB: fix

1512   *

1513   * Revision 1.26  2006/10/10 21:42:42  blueyed

1514   * Optimization: only collect $col_info, if $log_queries is enabled. TODO.

1515   *

1516   * Revision 1.25  2006/10/10 21:24:29  blueyed

1517   * Fix for the optimization

1518   *

1519   * Revision 1.24  2006/10/10 21:21:40  blueyed

1520   * Fixed possible SQL error, if table_options get used and theres a semicolon at the end of query; +optimization

1521   *

1522   * Revision 1.23  2006/10/10 21:17:42  blueyed

1523   * Fixed possible fatal error while collecting col_info for CREATE and DROP queries

1524   */
1525  ?>


Généré le : Thu Nov 29 23:58:50 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics