[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/joomla/database/src/ -> DatabaseQuery.php (source)

   1  <?php
   2  /**
   3   * Part of the Joomla Framework Database Package
   4   *
   5   * @copyright  Copyright (C) 2005 - 2021 Open Source Matters, Inc. All rights reserved.
   6   * @license    GNU General Public License version 2 or later; see LICENSE
   7   */
   8  
   9  namespace Joomla\Database;
  10  
  11  use Joomla\Database\Exception\QueryTypeAlreadyDefinedException;
  12  use Joomla\Database\Exception\UnknownTypeException;
  13  
  14  /**
  15   * Joomla Framework Query Building Class.
  16   *
  17   * @since  1.0
  18   *
  19   * @property-read  array                      $bounded             Holds key / value pair of bound objects.
  20   * @property-read  array                      $parameterMapping    Mapping array for parameter types.
  21   * @property-read  DatabaseInterface          $db                  The database driver.
  22   * @property-read  string                     $sql                 The SQL query (if a direct query string was provided).
  23   * @property-read  string                     $type                The query type.
  24   * @property-read  string|null                $alias               The query alias.
  25   * @property-read  Query\QueryElement         $element             The query element for a generic query (type = null).
  26   * @property-read  Query\QueryElement         $select              The select element.
  27   * @property-read  Query\QueryElement         $delete              The delete element.
  28   * @property-read  Query\QueryElement         $update              The update element.
  29   * @property-read  Query\QueryElement         $insert              The insert element.
  30   * @property-read  Query\QueryElement         $from                The from element.
  31   * @property-read  Query\QueryElement[]|null  $join                The join elements.
  32   * @property-read  Query\QueryElement         $set                 The set element.
  33   * @property-read  Query\QueryElement         $where               The where element.
  34   * @property-read  Query\QueryElement         $group               The group element.
  35   * @property-read  Query\QueryElement         $having              The having element.
  36   * @property-read  Query\QueryElement         $columns             The column list for an INSERT statement.
  37   * @property-read  Query\QueryElement         $values              The values list for an INSERT statement.
  38   * @property-read  Query\QueryElement         $order               The order element.
  39   * @property-read  boolean                    $autoIncrementField  The auto increment insert field element.
  40   * @property-read  Query\QueryElement         $call                The call element.
  41   * @property-read  Query\QueryElement         $exec                The exec element.
  42   * @property-read  Query\QueryElement[]|null  $merge               The list of query elements.
  43   * @property-read  DatabaseQuery|null         $querySet            The query object.
  44   * @property-read  array|null                 $selectRowNumber     Details of window function.
  45   * @property-read  string[]                   $nullDatetimeList    The list of zero or null representation of a datetime.
  46   * @property-read  integer|null               $offset              The offset for the result set.
  47   * @property-read  integer|null               $limit               The limit for the result set.
  48   * @property-read  integer                    $preparedIndex       An internal index for the bindArray function for unique prepared parameters.
  49   */
  50  abstract class DatabaseQuery implements QueryInterface
  51  {
  52      /**
  53       * Holds key / value pair of bound objects.
  54       *
  55       * @var    array
  56       * @since  2.0.0
  57       */
  58      protected $bounded = [];
  59  
  60      /**
  61       * Mapping array for parameter types.
  62       *
  63       * @var    array
  64       * @since  2.0.0
  65       */
  66      protected $parameterMapping = [
  67          ParameterType::BOOLEAN      => ParameterType::BOOLEAN,
  68          ParameterType::INTEGER      => ParameterType::INTEGER,
  69          ParameterType::LARGE_OBJECT => ParameterType::LARGE_OBJECT,
  70          ParameterType::NULL         => ParameterType::NULL,
  71          ParameterType::STRING       => ParameterType::STRING,
  72      ];
  73  
  74      /**
  75       * The database driver.
  76       *
  77       * @var    DatabaseInterface
  78       * @since  1.0
  79       */
  80      protected $db;
  81  
  82      /**
  83       * The SQL query (if a direct query string was provided).
  84       *
  85       * @var    string
  86       * @since  1.0
  87       */
  88      protected $sql;
  89  
  90      /**
  91       * The query type.
  92       *
  93       * @var    string|null
  94       * @since  1.0
  95       */
  96      protected $type = '';
  97  
  98      /**
  99       * The query alias.
 100       *
 101       * @var    string|null
 102       * @since  2.0.0
 103       */
 104      protected $alias = null;
 105  
 106      /**
 107       * The query element for a generic query (type = null).
 108       *
 109       * @var    Query\QueryElement
 110       * @since  1.0
 111       */
 112      protected $element;
 113  
 114      /**
 115       * The select element.
 116       *
 117       * @var    Query\QueryElement
 118       * @since  1.0
 119       */
 120      protected $select;
 121  
 122      /**
 123       * The delete element.
 124       *
 125       * @var    Query\QueryElement
 126       * @since  1.0
 127       */
 128      protected $delete;
 129  
 130      /**
 131       * The update element.
 132       *
 133       * @var    Query\QueryElement
 134       * @since  1.0
 135       */
 136      protected $update;
 137  
 138      /**
 139       * The insert element.
 140       *
 141       * @var    Query\QueryElement
 142       * @since  1.0
 143       */
 144      protected $insert;
 145  
 146      /**
 147       * The from element.
 148       *
 149       * @var    Query\QueryElement
 150       * @since  1.0
 151       */
 152      protected $from;
 153  
 154      /**
 155       * The join elements.
 156       *
 157       * @var    Query\QueryElement[]
 158       * @since  1.0
 159       */
 160      protected $join;
 161  
 162      /**
 163       * The set element.
 164       *
 165       * @var    Query\QueryElement
 166       * @since  1.0
 167       */
 168      protected $set;
 169  
 170      /**
 171       * The where element.
 172       *
 173       * @var    Query\QueryElement
 174       * @since  1.0
 175       */
 176      protected $where;
 177  
 178      /**
 179       * The group by element.
 180       *
 181       * @var    Query\QueryElement
 182       * @since  1.0
 183       */
 184      protected $group;
 185  
 186      /**
 187       * The having element.
 188       *
 189       * @var    Query\QueryElement
 190       * @since  1.0
 191       */
 192      protected $having;
 193  
 194      /**
 195       * The column list for an INSERT statement.
 196       *
 197       * @var    Query\QueryElement
 198       * @since  1.0
 199       */
 200      protected $columns;
 201  
 202      /**
 203       * The values list for an INSERT statement.
 204       *
 205       * @var    Query\QueryElement
 206       * @since  1.0
 207       */
 208      protected $values;
 209  
 210      /**
 211       * The order element.
 212       *
 213       * @var    Query\QueryElement
 214       * @since  1.0
 215       */
 216      protected $order;
 217  
 218      /**
 219       * The auto increment insert field element.
 220       *
 221       * @var    boolean
 222       * @since  1.0
 223       */
 224      protected $autoIncrementField = false;
 225  
 226      /**
 227       * The call element.
 228       *
 229       * @var    Query\QueryElement
 230       * @since  1.0
 231       */
 232      protected $call;
 233  
 234      /**
 235       * The exec element.
 236       *
 237       * @var    Query\QueryElement
 238       * @since  1.0
 239       */
 240      protected $exec;
 241  
 242      /**
 243       * The list of query elements, which may include UNION, UNION ALL, EXCEPT and INTERSECT.
 244       *
 245       * @var    Query\QueryElement[]
 246       * @since  2.0.0
 247       */
 248      protected $merge;
 249  
 250      /**
 251       * The query object.
 252       *
 253       * @var    Query\DatabaseQuery
 254       * @since  2.0.0
 255       */
 256      protected $querySet;
 257  
 258      /**
 259       * Details of window function.
 260       *
 261       * @var    array|null
 262       * @since  2.0.0
 263       */
 264      protected $selectRowNumber;
 265  
 266      /**
 267       * The list of zero or null representation of a datetime.
 268       *
 269       * @var    string[]
 270       * @since  2.0.0
 271       */
 272      protected $nullDatetimeList = [];
 273  
 274      /**
 275       * The offset for the result set.
 276       *
 277       * @var    integer|null
 278       * @since  2.0.0
 279       */
 280      protected $offset;
 281  
 282      /**
 283       * The limit for the result set.
 284       *
 285       * @var    integer|null
 286       * @since  2.0.0
 287       */
 288      protected $limit;
 289  
 290      /**
 291       * An internal index for the bindArray function for unique prepared parameters.
 292       *
 293       * @var    integer
 294       * @since  2.0.0
 295       */
 296      protected $preparedIndex = 0;
 297  
 298      /**
 299       * Class constructor.
 300       *
 301       * @param   DatabaseInterface  $db  The database driver.
 302       *
 303       * @since   1.0
 304       */
 305  	public function __construct(DatabaseInterface $db = null)
 306      {
 307          $this->db = $db;
 308      }
 309  
 310      /**
 311       * Magic function to convert the query to a string.
 312       *
 313       * @return  string    The completed query.
 314       *
 315       * @since   1.0
 316       */
 317  	public function __toString()
 318      {
 319          if ($this->sql)
 320          {
 321              return $this->processLimit($this->sql, $this->limit, $this->offset);
 322          }
 323  
 324          $query = '';
 325  
 326          switch ($this->type)
 327          {
 328              case 'element':
 329                  $query .= (string) $this->element;
 330  
 331                  break;
 332  
 333              case 'select':
 334                  $query .= (string) $this->select;
 335                  $query .= (string) $this->from;
 336  
 337                  if ($this->join)
 338                  {
 339                      // Special case for joins
 340                      foreach ($this->join as $join)
 341                      {
 342                          $query .= (string) $join;
 343                      }
 344                  }
 345  
 346                  if ($this->where)
 347                  {
 348                      $query .= (string) $this->where;
 349                  }
 350  
 351                  if ($this->selectRowNumber === null)
 352                  {
 353                      if ($this->group)
 354                      {
 355                          $query .= (string) $this->group;
 356                      }
 357  
 358                      if ($this->having)
 359                      {
 360                          $query .= (string) $this->having;
 361                      }
 362  
 363                      if ($this->merge)
 364                      {
 365                          // Special case for merge
 366                          foreach ($this->merge as $element)
 367                          {
 368                              $query .= (string) $element;
 369                          }
 370                      }
 371                  }
 372  
 373                  if ($this->order)
 374                  {
 375                      $query .= (string) $this->order;
 376                  }
 377  
 378                  break;
 379  
 380              case 'querySet':
 381                  $query = $this->querySet;
 382  
 383                  if ($query->order || ($query->limit || $query->offset))
 384                  {
 385                      // If ORDER BY or LIMIT statement exist then parentheses is required for the first query
 386                      $query = "($query)";
 387                  }
 388  
 389                  if ($this->merge)
 390                  {
 391                      // Special case for merge
 392                      foreach ($this->merge as $element)
 393                      {
 394                          $query .= (string) $element;
 395                      }
 396                  }
 397  
 398                  if ($this->order)
 399                  {
 400                      $query .= (string) $this->order;
 401                  }
 402  
 403                  break;
 404  
 405              case 'delete':
 406                  $query .= (string) $this->delete;
 407                  $query .= (string) $this->from;
 408  
 409                  if ($this->join)
 410                  {
 411                      // Special case for joins
 412                      foreach ($this->join as $join)
 413                      {
 414                          $query .= (string) $join;
 415                      }
 416                  }
 417  
 418                  if ($this->where)
 419                  {
 420                      $query .= (string) $this->where;
 421                  }
 422  
 423                  break;
 424  
 425              case 'update':
 426                  $query .= (string) $this->update;
 427  
 428                  if ($this->join)
 429                  {
 430                      // Special case for joins
 431                      foreach ($this->join as $join)
 432                      {
 433                          $query .= (string) $join;
 434                      }
 435                  }
 436  
 437                  $query .= (string) $this->set;
 438  
 439                  if ($this->where)
 440                  {
 441                      $query .= (string) $this->where;
 442                  }
 443  
 444                  break;
 445  
 446              case 'insert':
 447                  $query .= (string) $this->insert;
 448  
 449                  // Set method
 450                  if ($this->set)
 451                  {
 452                      $query .= (string) $this->set;
 453                  }
 454                  elseif ($this->values)
 455                  {
 456                      // Columns-Values method
 457                      if ($this->columns)
 458                      {
 459                          $query .= (string) $this->columns;
 460                      }
 461  
 462                      $elements = $this->values->getElements();
 463  
 464                      if (!($elements[0] instanceof $this))
 465                      {
 466                          $query .= ' VALUES ';
 467                      }
 468  
 469                      $query .= (string) $this->values;
 470                  }
 471  
 472                  break;
 473  
 474              case 'call':
 475                  $query .= (string) $this->call;
 476  
 477                  break;
 478  
 479              case 'exec':
 480                  $query .= (string) $this->exec;
 481  
 482                  break;
 483          }
 484  
 485          $query = $this->processLimit($query, $this->limit, $this->offset);
 486  
 487          if ($this->type === 'select' && $this->alias !== null)
 488          {
 489              $query = '(' . $query . ') AS ' . $this->alias;
 490          }
 491  
 492          return $query;
 493      }
 494  
 495      /**
 496       * Magic function to get protected variable value
 497       *
 498       * @param   string  $name  The name of the variable.
 499       *
 500       * @return  mixed
 501       *
 502       * @since   1.0
 503       */
 504  	public function __get($name)
 505      {
 506          if (property_exists($this, $name))
 507          {
 508              return $this->$name;
 509          }
 510  
 511          $trace = debug_backtrace();
 512          trigger_error(
 513              'Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'],
 514              E_USER_NOTICE
 515          );
 516      }
 517  
 518      /**
 519       * Add a single column, or array of columns to the CALL clause of the query.
 520       *
 521       * Usage:
 522       * $query->call('a.*')->call('b.id');
 523       * $query->call(array('a.*', 'b.id'));
 524       *
 525       * @param   mixed  $columns  A string or an array of field names.
 526       *
 527       * @return  $this
 528       *
 529       * @since   1.0
 530       * @throws  QueryTypeAlreadyDefinedException if the query type has already been defined
 531       */
 532  	public function call($columns)
 533      {
 534          if ($this->type !== null && $this->type !== '' && $this->type !== 'call')
 535          {
 536              throw new QueryTypeAlreadyDefinedException(
 537                  \sprintf(
 538                      'Cannot set the query type to "call" as the query type is already set to "%s".'
 539                          . ' You should either call the `clear()` method to reset the type or create a new query object.',
 540                      $this->type
 541                  )
 542              );
 543          }
 544  
 545          $this->type = 'call';
 546  
 547          if ($this->call === null)
 548          {
 549              $this->call = new Query\QueryElement('CALL', $columns);
 550          }
 551          else
 552          {
 553              $this->call->append($columns);
 554          }
 555  
 556          return $this;
 557      }
 558  
 559      /**
 560       * Casts a value to a char.
 561       *
 562       * Ensure that the value is properly quoted before passing to the method.
 563       *
 564       * Usage:
 565       * $query->select($query->castAs('CHAR', 'a'));
 566       *
 567       * @param   string  $type    The type of string to cast as.
 568       * @param   string  $value   The value to cast as a char.
 569       * @param   string  $length  Optionally specify the length of the field (if the type supports it otherwise
 570       *                           ignored).
 571       *
 572       * @return  string  SQL statement to cast the value as a char type.
 573       *
 574       * @since   1.0
 575       */
 576  	public function castAs(string $type, string $value, ?string $length = null)
 577      {
 578          switch (strtoupper($type))
 579          {
 580              case 'CHAR':
 581                  return $value;
 582  
 583              default:
 584                  throw new UnknownTypeException(
 585                      sprintf(
 586                          'Type %s was not recognised by the database driver as valid for casting',
 587                          $type
 588                      )
 589                  );
 590          }
 591      }
 592  
 593      /**
 594       * Casts a value to a char.
 595       *
 596       * Ensure that the value is properly quoted before passing to the method.
 597       *
 598       * Usage:
 599       * $query->select($query->castAsChar('a'));
 600       *
 601       * @param   string  $value  The value to cast as a char.
 602       *
 603       * @return  string  SQL statement to cast the value as a char type.
 604       *
 605       * @since       1.0
 606       * @deprecated  3.0  Use $query->castAs('CHAR', $value)
 607       */
 608  	public function castAsChar($value)
 609      {
 610          return $this->castAs('CHAR', $value);
 611      }
 612  
 613      /**
 614       * Gets the number of characters in a string.
 615       *
 616       * Note, use 'length' to find the number of bytes in a string.
 617       *
 618       * Usage:
 619       * $query->select($query->charLength('a'));
 620       *
 621       * @param   string       $field      A value.
 622       * @param   string|null  $operator   Comparison operator between charLength integer value and $condition
 623       * @param   string|null  $condition  Integer value to compare charLength with.
 624       *
 625       * @return  string  The required char length call.
 626       *
 627       * @since   1.0
 628       */
 629  	public function charLength($field, $operator = null, $condition = null)
 630      {
 631          $statement = 'CHAR_LENGTH(' . $field . ')';
 632  
 633          if ($operator !== null && $condition !== null)
 634          {
 635              $statement .= ' ' . $operator . ' ' . $condition;
 636          }
 637  
 638          return $statement;
 639      }
 640  
 641      /**
 642       * Clear data from the query or a specific clause of the query.
 643       *
 644       * @param   string  $clause  Optionally, the name of the clause to clear, or nothing to clear the whole query.
 645       *
 646       * @return  $this
 647       *
 648       * @since   1.0
 649       */
 650  	public function clear($clause = null)
 651      {
 652          $this->sql = null;
 653  
 654          switch ($clause)
 655          {
 656              case 'alias':
 657                  $this->alias = null;
 658                  break;
 659  
 660              case 'select':
 661                  $this->select          = null;
 662                  $this->type            = null;
 663                  $this->selectRowNumber = null;
 664  
 665                  break;
 666  
 667              case 'delete':
 668                  $this->delete = null;
 669                  $this->type   = null;
 670  
 671                  break;
 672  
 673              case 'update':
 674                  $this->update = null;
 675                  $this->type   = null;
 676  
 677                  break;
 678  
 679              case 'insert':
 680                  $this->insert             = null;
 681                  $this->type               = null;
 682                  $this->autoIncrementField = null;
 683  
 684                  break;
 685  
 686              case 'querySet':
 687                  $this->querySet = null;
 688                  $this->type     = null;
 689  
 690                  break;
 691  
 692              case 'from':
 693                  $this->from = null;
 694  
 695                  break;
 696  
 697              case 'join':
 698                  $this->join = null;
 699  
 700                  break;
 701  
 702              case 'set':
 703                  $this->set = null;
 704  
 705                  break;
 706  
 707              case 'where':
 708                  $this->where = null;
 709  
 710                  break;
 711  
 712              case 'group':
 713                  $this->group = null;
 714  
 715                  break;
 716  
 717              case 'having':
 718                  $this->having = null;
 719  
 720                  break;
 721  
 722              case 'merge':
 723                  $this->merge = null;
 724  
 725                  break;
 726  
 727              case 'order':
 728                  $this->order = null;
 729  
 730                  break;
 731  
 732              case 'columns':
 733                  $this->columns = null;
 734  
 735                  break;
 736  
 737              case 'values':
 738                  $this->values = null;
 739  
 740                  break;
 741  
 742              case 'exec':
 743                  $this->exec = null;
 744                  $this->type = null;
 745  
 746                  break;
 747  
 748              case 'call':
 749                  $this->call = null;
 750                  $this->type = null;
 751  
 752                  break;
 753  
 754              case 'limit':
 755                  $this->offset = 0;
 756                  $this->limit  = 0;
 757  
 758                  break;
 759  
 760              case 'offset':
 761                  $this->offset = 0;
 762  
 763                  break;
 764  
 765              case 'bounded':
 766                  $this->bounded = [];
 767  
 768                  break;
 769  
 770              default:
 771                  $this->type               = null;
 772                  $this->alias              = null;
 773                  $this->bounded            = [];
 774                  $this->select             = null;
 775                  $this->selectRowNumber    = null;
 776                  $this->delete             = null;
 777                  $this->update             = null;
 778                  $this->insert             = null;
 779                  $this->querySet           = null;
 780                  $this->from               = null;
 781                  $this->join               = null;
 782                  $this->set                = null;
 783                  $this->where              = null;
 784                  $this->group              = null;
 785                  $this->having             = null;
 786                  $this->merge              = null;
 787                  $this->order              = null;
 788                  $this->columns            = null;
 789                  $this->values             = null;
 790                  $this->autoIncrementField = null;
 791                  $this->exec               = null;
 792                  $this->call               = null;
 793                  $this->offset             = 0;
 794                  $this->limit              = 0;
 795  
 796                  break;
 797          }
 798  
 799          return $this;
 800      }
 801  
 802      /**
 803       * Adds a column, or array of column names that would be used for an INSERT INTO statement.
 804       *
 805       * @param   array|string  $columns  A column name, or array of column names.
 806       *
 807       * @return  $this
 808       *
 809       * @since   1.0
 810       */
 811  	public function columns($columns)
 812      {
 813          if ($this->columns === null)
 814          {
 815              $this->columns = new Query\QueryElement('()', $columns);
 816          }
 817          else
 818          {
 819              $this->columns->append($columns);
 820          }
 821  
 822          return $this;
 823      }
 824  
 825      /**
 826       * Concatenates an array of column names or values.
 827       *
 828       * Usage:
 829       * $query->select($query->concatenate(array('a', 'b')));
 830       *
 831       * @param   string[]     $values     An array of values to concatenate.
 832       * @param   string|null  $separator  As separator to place between each value.
 833       *
 834       * @return  string  The concatenated values.
 835       *
 836       * @since   1.0
 837       */
 838  	public function concatenate($values, $separator = null)
 839      {
 840          if ($separator !== null)
 841          {
 842              return 'CONCATENATE(' . implode(' || ' . $this->quote($separator) . ' || ', $values) . ')';
 843          }
 844  
 845          return 'CONCATENATE(' . implode(' || ', $values) . ')';
 846      }
 847  
 848      /**
 849       * Gets the current date and time.
 850       *
 851       * Usage:
 852       * $query->where('published_up < '.$query->currentTimestamp());
 853       *
 854       * @return  string
 855       *
 856       * @since   1.0
 857       */
 858  	public function currentTimestamp()
 859      {
 860          return 'CURRENT_TIMESTAMP()';
 861      }
 862  
 863      /**
 864       * Add to the current date and time.
 865       *
 866       * Usage:
 867       * $query->select($query->dateAdd());
 868       *
 869       * Prefixing the interval with a - (negative sign) will cause subtraction to be used.
 870       * Note: Not all drivers support all units.
 871       *
 872       * @param   string  $date      The db quoted string representation of the date to add to. May be date or datetime
 873       * @param   string  $interval  The string representation of the appropriate number of units
 874       * @param   string  $datePart  The part of the date to perform the addition on
 875       *
 876       * @return  string  The string with the appropriate sql for addition of dates
 877       *
 878       * @link    https://dev.mysql.com/doc/en/date-and-time-functions.html
 879       * @since   1.5.0
 880       */
 881  	public function dateAdd($date, $interval, $datePart)
 882      {
 883          return 'DATE_ADD(' . $date . ', INTERVAL ' . $interval . ' ' . $datePart . ')';
 884      }
 885  
 886      /**
 887       * Returns a PHP date() function compliant date format for the database driver.
 888       *
 889       * This method is provided for use where the query object is passed to a function for modification.
 890       * If you have direct access to the database object, it is recommended you use the getDateFormat method directly.
 891       *
 892       * @return  string  The format string.
 893       *
 894       * @since   1.0
 895       * @throws  \RuntimeException
 896       */
 897  	public function dateFormat()
 898      {
 899          if (!($this->db instanceof DatabaseInterface))
 900          {
 901              throw new \RuntimeException(sprintf('A %s instance is not set to the query object.', DatabaseInterface::class));
 902          }
 903  
 904          return $this->db->getDateFormat();
 905      }
 906  
 907      /**
 908       * Creates a HTML formatted dump of the query for debugging purposes.
 909       *
 910       * Usage:
 911       * echo $query->dump();
 912       *
 913       * @return  string
 914       *
 915       * @since   1.0
 916       * @deprecated  3.0  Deprecated without replacement
 917       */
 918  	public function dump()
 919      {
 920          trigger_deprecation(
 921              'joomla/database',
 922              '2.0.0',
 923              '%s() is deprecated and will be removed in 3.0.',
 924              __METHOD__
 925          );
 926  
 927          return '<pre class="jdatabasequery">' . str_replace('#__', $this->db->getPrefix(), $this) . '</pre>';
 928      }
 929  
 930      /**
 931       * Add a table name to the DELETE clause of the query.
 932       *
 933       * Usage:
 934       * $query->delete('#__a')->where('id = 1');
 935       *
 936       * @param   string  $table  The name of the table to delete from.
 937       *
 938       * @return  $this
 939       *
 940       * @since   1.0
 941       * @throws  QueryTypeAlreadyDefinedException if the query type has already been defined
 942       */
 943  	public function delete($table = null)
 944      {
 945          if ($this->type !== null && $this->type !== '' && $this->type !== 'delete')
 946          {
 947              throw new QueryTypeAlreadyDefinedException(
 948                  \sprintf(
 949                      'Cannot set the query type to "delete" as the query type is already set to "%s".'
 950                          . ' You should either call the `clear()` method to reset the type or create a new query object.',
 951                      $this->type
 952                  )
 953              );
 954          }
 955  
 956          $this->type   = 'delete';
 957          $this->delete = new Query\QueryElement('DELETE', null);
 958  
 959          if (!empty($table))
 960          {
 961              $this->from($table);
 962          }
 963  
 964          return $this;
 965      }
 966  
 967      /**
 968       * Alias for escape method
 969       *
 970       * @param   string   $text   The string to be escaped.
 971       * @param   boolean  $extra  Optional parameter to provide extra escaping.
 972       *
 973       * @return  string  The escaped string.
 974       *
 975       * @since   1.0
 976       * @throws  \RuntimeException if the internal db property is not a valid object.
 977       */
 978      public function e($text, $extra = false)
 979      {
 980          return $this->escape($text, $extra);
 981      }
 982  
 983      /**
 984       * Method to escape a string for usage in an SQL statement.
 985       *
 986       * This method is provided for use where the query object is passed to a function for modification.
 987       * If you have direct access to the database object, it is recommended you use the escape method directly.
 988       *
 989       * Note that 'e' is an alias for this method as it is in DatabaseDriver.
 990       *
 991       * @param   string   $text   The string to be escaped.
 992       * @param   boolean  $extra  Optional parameter to provide extra escaping.
 993       *
 994       * @return  string  The escaped string.
 995       *
 996       * @since   1.0
 997       * @throws  \RuntimeException if the internal db property is not a valid object.
 998       */
 999  	public function escape($text, $extra = false)
1000      {
1001          if (!($this->db instanceof DatabaseInterface))
1002          {
1003              throw new \RuntimeException(sprintf('A %s instance is not set to the query object.', DatabaseInterface::class));
1004          }
1005  
1006          return $this->db->escape($text, $extra);
1007      }
1008  
1009      /**
1010       * Add a single column, or array of columns to the EXEC clause of the query.
1011       *
1012       * Usage:
1013       * $query->exec('a.*')->exec('b.id');
1014       * $query->exec(array('a.*', 'b.id'));
1015       *
1016       * @param   array|string  $columns  A string or an array of field names.
1017       *
1018       * @return  $this
1019       *
1020       * @since   1.0
1021       * @throws  QueryTypeAlreadyDefinedException if the query type has already been defined
1022       */
1023  	public function exec($columns)
1024      {
1025          if ($this->type !== null && $this->type !== '' && $this->type !== 'exec')
1026          {
1027              throw new QueryTypeAlreadyDefinedException(
1028                  \sprintf(
1029                      'Cannot set the query type to "exec" as the query type is already set to "%s".'
1030                          . ' You should either call the `clear()` method to reset the type or create a new query object.',
1031                      $this->type
1032                  )
1033              );
1034          }
1035  
1036          $this->type = 'exec';
1037  
1038          if ($this->exec === null)
1039          {
1040              $this->exec = new Query\QueryElement('EXEC', $columns);
1041          }
1042          else
1043          {
1044              $this->exec->append($columns);
1045          }
1046  
1047          return $this;
1048      }
1049  
1050      /**
1051       * Find a value in a varchar used like a set.
1052       *
1053       * Ensure that the value is an integer before passing to the method.
1054       *
1055       * Usage:
1056       * $query->findInSet((int) $parent->id, 'a.assigned_cat_ids')
1057       *
1058       * @param   string  $value  The value to search for.
1059       * @param   string  $set    The set of values.
1060       *
1061       * @return  string  A representation of the MySQL find_in_set() function for the driver.
1062       *
1063       * @since   1.5.0
1064       */
1065  	public function findInSet($value, $set)
1066      {
1067          return '';
1068      }
1069  
1070      /**
1071       * Add a table to the FROM clause of the query.
1072       *
1073       * Usage:
1074       * $query->select('*')->from('#__a');
1075       * $query->select('*')->from($subquery->alias('a'));
1076       *
1077       * @param   string|DatabaseQuery  $table  The name of the table or a DatabaseQuery object (or a child of it) with alias set.
1078       *
1079       * @return  $this
1080       *
1081       * @since   1.0
1082       * @throws  \RuntimeException
1083       */
1084  	public function from($table)
1085      {
1086          if ($table instanceof $this && $table->alias === null)
1087          {
1088              throw new \RuntimeException('JLIB_DATABASE_ERROR_NULL_SUBQUERY_ALIAS');
1089          }
1090  
1091          if ($this->from === null)
1092          {
1093              $this->from = new Query\QueryElement('FROM', $table);
1094          }
1095          else
1096          {
1097              $this->from->append($table);
1098          }
1099  
1100          return $this;
1101      }
1102  
1103      /**
1104       * Add alias for current query.
1105       *
1106       * Usage:
1107       * $query->select('*')->from('#__a')->alias('subquery');
1108       *
1109       * @param   string  $alias  Alias used for a JDatabaseQuery.
1110       *
1111       * @return  $this
1112       *
1113       * @since   2.0.0
1114       */
1115  	public function alias($alias)
1116      {
1117          $this->alias = $alias;
1118  
1119          return $this;
1120      }
1121  
1122      /**
1123       * Used to get a string to extract year from date column.
1124       *
1125       * Usage:
1126       * $query->select($query->year($query->quoteName('dateColumn')));
1127       *
1128       * @param   string  $date  Date column containing year to be extracted.
1129       *
1130       * @return  string  Returns string to extract year from a date.
1131       *
1132       * @since   1.0
1133       */
1134  	public function year($date)
1135      {
1136          return 'YEAR(' . $date . ')';
1137      }
1138  
1139      /**
1140       * Used to get a string to extract month from date column.
1141       *
1142       * Usage:
1143       * $query->select($query->month($query->quoteName('dateColumn')));
1144       *
1145       * @param   string  $date  Date column containing month to be extracted.
1146       *
1147       * @return  string  Returns string to extract month from a date.
1148       *
1149       * @since   1.0
1150       */
1151  	public function month($date)
1152      {
1153          return 'MONTH(' . $date . ')';
1154      }
1155  
1156      /**
1157       * Used to get a string to extract day from date column.
1158       *
1159       * Usage:
1160       * $query->select($query->day($query->quoteName('dateColumn')));
1161       *
1162       * @param   string  $date  Date column containing day to be extracted.
1163       *
1164       * @return  string  Returns string to extract day from a date.
1165       *
1166       * @since   1.0
1167       */
1168  	public function day($date)
1169      {
1170          return 'DAY(' . $date . ')';
1171      }
1172  
1173      /**
1174       * Used to get a string to extract hour from date column.
1175       *
1176       * Usage:
1177       * $query->select($query->hour($query->quoteName('dateColumn')));
1178       *
1179       * @param   string  $date  Date column containing hour to be extracted.
1180       *
1181       * @return  string  Returns string to extract hour from a date.
1182       *
1183       * @since   1.0
1184       */
1185  	public function hour($date)
1186      {
1187          return 'HOUR(' . $date . ')';
1188      }
1189  
1190      /**
1191       * Used to get a string to extract minute from date column.
1192       *
1193       * Usage:
1194       * $query->select($query->minute($query->quoteName('dateColumn')));
1195       *
1196       * @param   string  $date  Date column containing minute to be extracted.
1197       *
1198       * @return  string  Returns string to extract minute from a date.
1199       *
1200       * @since   1.0
1201       */
1202  	public function minute($date)
1203      {
1204          return 'MINUTE(' . $date . ')';
1205      }
1206  
1207      /**
1208       * Used to get a string to extract seconds from date column.
1209       *
1210       * Usage:
1211       * $query->select($query->second($query->quoteName('dateColumn')));
1212       *
1213       * @param   string  $date  Date column containing second to be extracted.
1214       *
1215       * @return  string  Returns string to extract second from a date.
1216       *
1217       * @since   1.0
1218       */
1219  	public function second($date)
1220      {
1221          return 'SECOND(' . $date . ')';
1222      }
1223  
1224      /**
1225       * Add a grouping column to the GROUP clause of the query.
1226       *
1227       * Usage:
1228       * $query->group('id');
1229       *
1230       * @param   array|string  $columns  A string or array of ordering columns.
1231       *
1232       * @return  $this
1233       *
1234       * @since   1.0
1235       */
1236  	public function group($columns)
1237      {
1238          if ($this->group === null)
1239          {
1240              $this->group = new Query\QueryElement('GROUP BY', $columns);
1241          }
1242          else
1243          {
1244              $this->group->append($columns);
1245          }
1246  
1247          return $this;
1248      }
1249  
1250      /**
1251       * A conditions to the HAVING clause of the query.
1252       *
1253       * Usage:
1254       * $query->group('id')->having('COUNT(id) > 5');
1255       *
1256       * @param   array|string  $conditions  A string or array of columns.
1257       * @param   string        $glue        The glue by which to join the conditions. Defaults to AND.
1258       *
1259       * @return  $this
1260       *
1261       * @since   1.0
1262       */
1263  	public function having($conditions, $glue = 'AND')
1264      {
1265          if ($this->having === null)
1266          {
1267              $glue         = strtoupper($glue);
1268              $this->having = new Query\QueryElement('HAVING', $conditions, " $glue ");
1269          }
1270          else
1271          {
1272              $this->having->append($conditions);
1273          }
1274  
1275          return $this;
1276      }
1277  
1278      /**
1279       * Add a table name to the INSERT clause of the query.
1280       *
1281       * Usage:
1282       * $query->insert('#__a')->set('id = 1');
1283       * $query->insert('#__a')->columns('id, title')->values('1,2')->values('3,4');
1284       * $query->insert('#__a')->columns('id, title')->values(array('1,2', '3,4'));
1285       *
1286       * @param   string   $table           The name of the table to insert data into.
1287       * @param   boolean  $incrementField  The name of the field to auto increment.
1288       *
1289       * @return  $this
1290       *
1291       * @since   1.0
1292       * @throws  QueryTypeAlreadyDefinedException if the query type has already been defined
1293       */
1294  	public function insert($table, $incrementField = false)
1295      {
1296          if ($this->type !== null && $this->type !== '' && $this->type !== 'insert')
1297          {
1298              throw new QueryTypeAlreadyDefinedException(
1299                  \sprintf(
1300                      'Cannot set the query type to "insert" as the query type is already set to "%s".'
1301                          . ' You should either call the `clear()` method to reset the type or create a new query object.',
1302                      $this->type
1303                  )
1304              );
1305          }
1306  
1307          $this->type               = 'insert';
1308          $this->insert             = new Query\QueryElement('INSERT INTO', $table);
1309          $this->autoIncrementField = $incrementField;
1310  
1311          return $this;
1312      }
1313  
1314      /**
1315       * Add a JOIN clause to the query.
1316       *
1317       * Usage:
1318       * $query->join('INNER', 'b', 'b.id = a.id);
1319       *
1320       * @param   string  $type       The type of join. This string is prepended to the JOIN keyword.
1321       * @param   string  $table      The name of table.
1322       * @param   string  $condition  The join condition.
1323       *
1324       * @return  $this
1325       *
1326       * @since   1.0
1327       */
1328  	public function join($type, $table, $condition = null)
1329      {
1330          $type = strtoupper($type) . ' JOIN';
1331  
1332          if ($condition !== null)
1333          {
1334              $this->join[] = new Query\QueryElement($type, [$table, $condition], ' ON ');
1335          }
1336          else
1337          {
1338              $this->join[] = new Query\QueryElement($type, $table);
1339          }
1340  
1341          return $this;
1342      }
1343  
1344      /**
1345       * Add an INNER JOIN clause to the query.
1346       *
1347       * Usage:
1348       * $query->innerJoin('b', 'b.id = a.id')->innerJoin('c', 'c.id = b.id');
1349       *
1350       * @param   string  $table      The name of table.
1351       * @param   string  $condition  The join condition.
1352       *
1353       * @return  $this
1354       *
1355       * @since   1.0
1356       */
1357  	public function innerJoin($table, $condition = null)
1358      {
1359          return $this->join('INNER', $table, $condition);
1360      }
1361  
1362      /**
1363       * Add an OUTER JOIN clause to the query.
1364       *
1365       * Usage:
1366       * $query->outerJoin('b', 'b.id = a.id')->leftJoin('c', 'c.id = b.id');
1367       *
1368       * @param   string  $table      The name of table.
1369       * @param   string  $condition  The join condition.
1370       *
1371       * @return  $this
1372       *
1373       * @since   1.0
1374       */
1375  	public function outerJoin($table, $condition = null)
1376      {
1377          return $this->join('OUTER', $table, $condition);
1378      }
1379  
1380      /**
1381       * Add a LEFT JOIN clause to the query.
1382       *
1383       * Usage:
1384       * $query->leftJoin('b', 'b.id = a.id')->leftJoin('c', 'c.id = b.id');
1385       *
1386       * @param   string  $table      The name of table.
1387       * @param   string  $condition  The join condition.
1388       *
1389       * @return  $this
1390       *
1391       * @since   1.0
1392       */
1393  	public function leftJoin($table, $condition = null)
1394      {
1395          return $this->join('LEFT', $table, $condition);
1396      }
1397  
1398      /**
1399       * Add a RIGHT JOIN clause to the query.
1400       *
1401       * Usage:
1402       * $query->rightJoin('b', 'b.id = a.id')->rightJoin('c', 'c.id = b.id');
1403       *
1404       * @param   string  $table      The name of table.
1405       * @param   string  $condition  The join condition.
1406       *
1407       * @return  $this
1408       *
1409       * @since   1.0
1410       */
1411  	public function rightJoin($table, $condition = null)
1412      {
1413          return $this->join('RIGHT', $table, $condition);
1414      }
1415  
1416      /**
1417       * Get the length of a string in bytes.
1418       *
1419       * Note, use 'charLength' to find the number of characters in a string.
1420       *
1421       * Usage:
1422       * query->where($query->length('a').' > 3');
1423       *
1424       * @param   string  $value  The string to measure.
1425       *
1426       * @return  integer
1427       *
1428       * @since   1.0
1429       */
1430  	public function length($value)
1431      {
1432          return 'LENGTH(' . $value . ')';
1433      }
1434  
1435      /**
1436       * Get the null or zero representation of a timestamp for the database driver.
1437       *
1438       * This method is provided for use where the query object is passed to a function for modification.
1439       * If you have direct access to the database object, it is recommended you use the nullDate method directly.
1440       *
1441       * Usage:
1442       * $query->where('modified_date <> '.$query->nullDate());
1443       *
1444       * @param   boolean  $quoted  Optionally wraps the null date in database quotes (true by default).
1445       *
1446       * @return  string  Null or zero representation of a timestamp.
1447       *
1448       * @since   1.0
1449       * @throws  \RuntimeException
1450       */
1451  	public function nullDate($quoted = true)
1452      {
1453          if (!($this->db instanceof DatabaseInterface))
1454          {
1455              throw new \RuntimeException(sprintf('A %s instance is not set to the query object.', DatabaseInterface::class));
1456          }
1457  
1458          $result = $this->db->getNullDate();
1459  
1460          if ($quoted)
1461          {
1462              return $this->db->quote($result);
1463          }
1464  
1465          return $result;
1466      }
1467  
1468      /**
1469       * Generate a SQL statement to check if column represents a zero or null datetime.
1470       *
1471       * Usage:
1472       * $query->where($query->isNullDatetime('modified_date'));
1473       *
1474       * @param   string  $column  A column name.
1475       *
1476       * @return  string
1477       *
1478       * @since   2.0.0
1479       */
1480  	public function isNullDatetime($column)
1481      {
1482          if (!$this->db instanceof DatabaseInterface)
1483          {
1484              throw new \RuntimeException(sprintf('A %s instance is not set to the query object.', DatabaseInterface::class));
1485          }
1486  
1487          if ($this->nullDatetimeList)
1488          {
1489              return "($column IN ("
1490              . implode(', ', $this->db->quote($this->nullDatetimeList))
1491              . ") OR $column IS NULL)";
1492          }
1493  
1494          return "$column IS NULL";
1495      }
1496  
1497      /**
1498       * Add a ordering column to the ORDER clause of the query.
1499       *
1500       * Usage:
1501       * $query->order('foo')->order('bar');
1502       * $query->order(array('foo','bar'));
1503       *
1504       * @param   array|string  $columns  A string or array of ordering columns.
1505       *
1506       * @return  $this
1507       *
1508       * @since   1.0
1509       */
1510  	public function order($columns)
1511      {
1512          if ($this->order === null)
1513          {
1514              $this->order = new Query\QueryElement('ORDER BY', $columns);
1515          }
1516          else
1517          {
1518              $this->order->append($columns);
1519          }
1520  
1521          return $this;
1522      }
1523  
1524      /**
1525       * Alias for quote method
1526       *
1527       * @param   array|string  $text    A string or an array of strings to quote.
1528       * @param   boolean       $escape  True (default) to escape the string, false to leave it unchanged.
1529       *
1530       * @return  string  The quoted input string.
1531       *
1532       * @since   1.0
1533       * @throws  \RuntimeException if the internal db property is not a valid object.
1534       */
1535      public function q($text, $escape = true)
1536      {
1537          return $this->quote($text, $escape);
1538      }
1539  
1540      /**
1541       * Method to quote and optionally escape a string to database requirements for insertion into the database.
1542       *
1543       * This method is provided for use where the query object is passed to a function for modification.
1544       * If you have direct access to the database object, it is recommended you use the quote method directly.
1545       *
1546       * Note that 'q' is an alias for this method as it is in DatabaseDriver.
1547       *
1548       * Usage:
1549       * $query->quote('fulltext');
1550       * $query->q('fulltext');
1551       * $query->q(array('option', 'fulltext'));
1552       *
1553       * @param   array|string  $text    A string or an array of strings to quote.
1554       * @param   boolean       $escape  True (default) to escape the string, false to leave it unchanged.
1555       *
1556       * @return  string  The quoted input string.
1557       *
1558       * @since   1.0
1559       * @throws  \RuntimeException if the internal db property is not a valid object.
1560       */
1561  	public function quote($text, $escape = true)
1562      {
1563          if (!($this->db instanceof DatabaseInterface))
1564          {
1565              throw new \RuntimeException(sprintf('A %s instance is not set to the query object.', DatabaseInterface::class));
1566          }
1567  
1568          return $this->db->quote($text, $escape);
1569      }
1570  
1571      /**
1572       * Alias for quoteName method
1573       *
1574       * @param   array|string  $name  The identifier name to wrap in quotes, or an array of identifier names to wrap in quotes.
1575       *                               Each type supports dot-notation name.
1576       * @param   array|string  $as    The AS query part associated to $name. It can be string or array, in latter case it has to be
1577       *                               same length of $name; if is null there will not be any AS part for string or array element.
1578       *
1579       * @return  array|string  The quote wrapped name, same type of $name.
1580       *
1581       * @since   1.0
1582       * @throws  \RuntimeException if the internal db property is not a valid object.
1583       */
1584      public function qn($name, $as = null)
1585      {
1586          return $this->quoteName($name, $as);
1587      }
1588  
1589      /**
1590       * Wrap an SQL statement identifier name such as column, table or database names in quotes to prevent injection
1591       * risks and reserved word conflicts.
1592       *
1593       * This method is provided for use where the query object is passed to a function for modification.
1594       * If you have direct access to the database object, it is recommended you use the quoteName method directly.
1595       *
1596       * Note that 'qn' is an alias for this method as it is in DatabaseDriver.
1597       *
1598       * Usage:
1599       * $query->quoteName('#__a');
1600       * $query->qn('#__a');
1601       *
1602       * @param   array|string  $name  The identifier name to wrap in quotes, or an array of identifier names to wrap in quotes.
1603       *                               Each type supports dot-notation name.
1604       * @param   array|string  $as    The AS query part associated to $name. It can be string or array, in latter case it has to be
1605       *                               same length of $name; if is null there will not be any AS part for string or array element.
1606       *
1607       * @return  array|string  The quote wrapped name, same type of $name.
1608       *
1609       * @since   1.0
1610       * @throws  \RuntimeException if the internal db property is not a valid object.
1611       */
1612  	public function quoteName($name, $as = null)
1613      {
1614          if (!($this->db instanceof DatabaseInterface))
1615          {
1616              throw new \RuntimeException(sprintf('A %s instance is not set to the query object.', DatabaseInterface::class));
1617          }
1618  
1619          return $this->db->quoteName($name, $as);
1620      }
1621  
1622      /**
1623       * Get the function to return a random floating-point value
1624       *
1625       * Usage:
1626       * $query->rand();
1627       *
1628       * @return  string
1629       *
1630       * @since   1.5.0
1631       */
1632  	public function rand()
1633      {
1634          return '';
1635      }
1636  
1637      /**
1638       * Get the regular expression operator
1639       *
1640       * Usage:
1641       * $query->where('field ' . $query->regexp($search));
1642       *
1643       * @param   string  $value  The regex pattern.
1644       *
1645       * @return  string
1646       *
1647       * @since   1.5.0
1648       */
1649  	public function regexp($value)
1650      {
1651          return ' ' . $value;
1652      }
1653  
1654      /**
1655       * Add a single column, or array of columns to the SELECT clause of the query.
1656       *
1657       * Note that you must not mix insert, update, delete and select method calls when building a query.
1658       * The select method can, however, be called multiple times in the same query.
1659       *
1660       * Usage:
1661       * $query->select('a.*')->select('b.id');
1662       * $query->select(array('a.*', 'b.id'));
1663       *
1664       * @param   array|string  $columns  A string or an array of field names.
1665       *
1666       * @return  $this
1667       *
1668       * @since   1.0
1669       * @throws  QueryTypeAlreadyDefinedException if the query type has already been defined
1670       */
1671  	public function select($columns)
1672      {
1673          if ($this->type !== null && $this->type !== '' && $this->type !== 'select')
1674          {
1675              throw new QueryTypeAlreadyDefinedException(
1676                  \sprintf(
1677                      'Cannot set the query type to "select" as the query type is already set to "%s".'
1678                          . ' You should either call the `clear()` method to reset the type or create a new query object.',
1679                      $this->type
1680                  )
1681              );
1682          }
1683  
1684          $this->type = 'select';
1685  
1686          if ($this->select === null)
1687          {
1688              $this->select = new Query\QueryElement('SELECT', $columns);
1689          }
1690          else
1691          {
1692              $this->select->append($columns);
1693          }
1694  
1695          return $this;
1696      }
1697  
1698      /**
1699       * Add a single condition string, or an array of strings to the SET clause of the query.
1700       *
1701       * Usage:
1702       * $query->set('a = 1')->set('b = 2');
1703       * $query->set(array('a = 1', 'b = 2');
1704       *
1705       * @param   array|string  $conditions  A string or array of string conditions.
1706       * @param   string        $glue        The glue by which to join the condition strings. Defaults to ,.
1707       *                                     Note that the glue is set on first use and cannot be changed.
1708       *
1709       * @return  $this
1710       *
1711       * @since   1.0
1712       */
1713  	public function set($conditions, $glue = ',')
1714      {
1715          if ($this->set === null)
1716          {
1717              $glue      = strtoupper($glue);
1718              $this->set = new Query\QueryElement('SET', $conditions, \PHP_EOL . "\t$glue ");
1719          }
1720          else
1721          {
1722              $this->set->append($conditions);
1723          }
1724  
1725          return $this;
1726      }
1727  
1728      /**
1729       * Sets the offset and limit for the result set, if the database driver supports it.
1730       *
1731       * Usage:
1732       * $query->setLimit(100, 0); (retrieve 100 rows, starting at first record)
1733       * $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th record)
1734       *
1735       * @param   integer  $limit   The limit for the result set
1736       * @param   integer  $offset  The offset for the result set
1737       *
1738       * @return  $this
1739       *
1740       * @since   2.0.0
1741       */
1742  	public function setLimit($limit = 0, $offset = 0)
1743      {
1744          $this->limit  = (int) $limit;
1745          $this->offset = (int) $offset;
1746  
1747          return $this;
1748      }
1749  
1750      /**
1751       * Allows a direct query to be provided to the database driver's setQuery() method, but still allow queries
1752       * to have bounded variables.
1753       *
1754       * Usage:
1755       * $query->setQuery('select * from #__users');
1756       *
1757       * @param   DatabaseQuery|string  $sql  A SQL query string or DatabaseQuery object
1758       *
1759       * @return  $this
1760       *
1761       * @since   1.0
1762       */
1763  	public function setQuery($sql)
1764      {
1765          $this->sql = $sql;
1766  
1767          return $this;
1768      }
1769  
1770      /**
1771       * Add a table name to the UPDATE clause of the query.
1772       *
1773       * Usage:
1774       * $query->update('#__foo')->set(...);
1775       *
1776       * @param   string  $table  A table to update.
1777       *
1778       * @return  $this
1779       *
1780       * @since   1.0
1781       * @throws  QueryTypeAlreadyDefinedException if the query type has already been defined
1782       */
1783  	public function update($table)
1784      {
1785          if ($this->type !== null && $this->type !== '' && $this->type !== 'update')
1786          {
1787              throw new QueryTypeAlreadyDefinedException(
1788                  \sprintf(
1789                      'Cannot set the query type to "update" as the query type is already set to "%s".'
1790                          . ' You should either call the `clear()` method to reset the type or create a new query object.',
1791                      $this->type
1792                  )
1793              );
1794          }
1795  
1796          $this->type   = 'update';
1797          $this->update = new Query\QueryElement('UPDATE', $table);
1798  
1799          return $this;
1800      }
1801  
1802      /**
1803       * Adds a tuple, or array of tuples that would be used as values for an INSERT INTO statement.
1804       *
1805       * Usage:
1806       * $query->values('1,2,3')->values('4,5,6');
1807       * $query->values(array('1,2,3', '4,5,6'));
1808       *
1809       * @param   array|string  $values  A single tuple, or array of tuples.
1810       *
1811       * @return  $this
1812       *
1813       * @since   1.0
1814       */
1815  	public function values($values)
1816      {
1817          if ($this->values === null)
1818          {
1819              $this->values = new Query\QueryElement('()', $values, '),(');
1820          }
1821          else
1822          {
1823              $this->values->append($values);
1824          }
1825  
1826          return $this;
1827      }
1828  
1829      /**
1830       * Add a single condition, or an array of conditions to the WHERE clause of the query.
1831       *
1832       * Usage:
1833       * $query->where('a = 1')->where('b = 2');
1834       * $query->where(array('a = 1', 'b = 2'));
1835       *
1836       * @param   array|string  $conditions  A string or array of where conditions.
1837       * @param   string        $glue        The glue by which to join the conditions. Defaults to AND.
1838       *                                     Note that the glue is set on first use and cannot be changed.
1839       *
1840       * @return  $this
1841       *
1842       * @since   1.0
1843       */
1844  	public function where($conditions, $glue = 'AND')
1845      {
1846          if ($this->where === null)
1847          {
1848              $glue        = strtoupper($glue);
1849              $this->where = new Query\QueryElement('WHERE', $conditions, " $glue ");
1850          }
1851          else
1852          {
1853              $this->where->append($conditions);
1854          }
1855  
1856          return $this;
1857      }
1858  
1859      /**
1860       * Add a WHERE IN statement to the query.
1861       *
1862       * Note that all values must be the same data type.
1863       *
1864       * Usage
1865       * $query->whereIn('id', [1, 2, 3]);
1866       *
1867       * @param   string        $keyName    Key name for the where clause
1868       * @param   array         $keyValues  Array of values to be matched
1869       * @param   array|string  $dataType   Constant corresponding to a SQL datatype. It can be an array, in this case it
1870       *                                    has to be same length of $keyValues
1871       *
1872       * @return  $this
1873       *
1874       * @since 2.0.0
1875       */
1876  	public function whereIn(string $keyName, array $keyValues, $dataType = ParameterType::INTEGER)
1877      {
1878          return $this->where(
1879              $keyName . ' IN (' . implode(',', $this->bindArray($keyValues, $dataType)) . ')'
1880          );
1881      }
1882  
1883      /**
1884       * Add a WHERE NOT IN statement to the query.
1885       *
1886       * Note that all values must be the same data type.
1887       *
1888       * Usage
1889       * $query->whereNotIn('id', [1, 2, 3]);
1890       *
1891       * @param   string        $keyName    Key name for the where clause
1892       * @param   array         $keyValues  Array of values to be matched
1893       * @param   array|string  $dataType   Constant corresponding to a SQL datatype. It can be an array, in this case it
1894       *                                    has to be same length of $keyValues
1895       *
1896       * @return  $this
1897       *
1898       * @since 2.0.0
1899       */
1900  	public function whereNotIn(string $keyName, array $keyValues, $dataType = ParameterType::INTEGER)
1901      {
1902          return $this->where(
1903              $keyName . ' NOT IN (' . implode(',', $this->bindArray($keyValues, $dataType)) . ')'
1904          );
1905      }
1906  
1907      /**
1908       * Extend the WHERE clause with a single condition or an array of conditions, with a potentially
1909       * different logical operator from the one in the current WHERE clause.
1910       *
1911       * Usage:
1912       * $query->where(array('a = 1', 'b = 2'))->extendWhere('XOR', array('c = 3', 'd = 4'));
1913       * will produce: WHERE ((a = 1 AND b = 2) XOR (c = 3 AND d = 4)
1914       *
1915       * @param   string  $outerGlue   The glue by which to join the conditions to the current WHERE conditions.
1916       * @param   mixed   $conditions  A string or array of WHERE conditions.
1917       * @param   string  $innerGlue   The glue by which to join the conditions. Defaults to AND.
1918       *
1919       * @return  $this
1920       *
1921       * @since   1.3.0
1922       */
1923  	public function extendWhere($outerGlue, $conditions, $innerGlue = 'AND')
1924      {
1925          // Replace the current WHERE with a new one which has the old one as an unnamed child.
1926          $this->where = new Query\QueryElement('WHERE', $this->where->setName('()'), " $outerGlue ");
1927  
1928          // Append the new conditions as a new unnamed child.
1929          $this->where->append(new Query\QueryElement('()', $conditions, " $innerGlue "));
1930  
1931          return $this;
1932      }
1933  
1934      /**
1935       * Extend the WHERE clause with an OR and a single condition or an array of conditions.
1936       *
1937       * Usage:
1938       * $query->where(array('a = 1', 'b = 2'))->orWhere(array('c = 3', 'd = 4'));
1939       * will produce: WHERE ((a = 1 AND b = 2) OR (c = 3 AND d = 4)
1940       *
1941       * @param   mixed   $conditions  A string or array of WHERE conditions.
1942       * @param   string  $glue        The glue by which to join the conditions. Defaults to AND.
1943       *
1944       * @return  $this
1945       *
1946       * @since   1.3.0
1947       */
1948  	public function orWhere($conditions, $glue = 'AND')
1949      {
1950          return $this->extendWhere('OR', $conditions, $glue);
1951      }
1952  
1953      /**
1954       * Extend the WHERE clause with an AND and a single condition or an array of conditions.
1955       *
1956       * Usage:
1957       * $query->where(array('a = 1', 'b = 2'))->andWhere(array('c = 3', 'd = 4'));
1958       * will produce: WHERE ((a = 1 AND b = 2) AND (c = 3 OR d = 4)
1959       *
1960       * @param   mixed   $conditions  A string or array of WHERE conditions.
1961       * @param   string  $glue        The glue by which to join the conditions. Defaults to OR.
1962       *
1963       * @return  $this
1964       *
1965       * @since   1.3.0
1966       */
1967  	public function andWhere($conditions, $glue = 'OR')
1968      {
1969          return $this->extendWhere('AND', $conditions, $glue);
1970      }
1971  
1972      /**
1973       * Method to add a variable to an internal array that will be bound to a prepared SQL statement before query execution.
1974       *
1975       * @param   array|string|integer  $key            The key that will be used in your SQL query to reference the value. Usually of
1976       *                                                the form ':key', but can also be an integer.
1977       * @param   mixed                 $value          The value that will be bound. It can be an array, in this case it has to be
1978       *                                                same length of $key; The value is passed by reference to support output
1979       *                                                parameters such as those possible with stored procedures.
1980       * @param   array|string          $dataType       Constant corresponding to a SQL datatype. It can be an array, in this case it
1981       *                                                has to be same length of $key
1982       * @param   integer               $length         The length of the variable. Usually required for OUTPUT parameters.
1983       * @param   array                 $driverOptions  Optional driver options to be used.
1984       *
1985       * @return  $this
1986       *
1987       * @since   1.5.0
1988       * @throws  \InvalidArgumentException
1989       */
1990  	public function bind($key, &$value, $dataType = ParameterType::STRING, $length = 0, $driverOptions = [])
1991      {
1992          if (!$key)
1993          {
1994              throw new \InvalidArgumentException('A key is required');
1995          }
1996  
1997          $key   = (array) $key;
1998          $count = \count($key);
1999  
2000          if (\is_array($value))
2001          {
2002              if ($count != \count($value))
2003              {
2004                  throw new \InvalidArgumentException('Array length of $key and $value are not equal');
2005              }
2006  
2007              reset($value);
2008          }
2009  
2010          if (\is_array($dataType) && $count != \count($dataType))
2011          {
2012              throw new \InvalidArgumentException('Array length of $key and $dataType are not equal');
2013          }
2014  
2015          foreach ($key as $index)
2016          {
2017              if (\is_array($value))
2018              {
2019                  $localValue = &$value[key($value)];
2020                  next($value);
2021              }
2022              else
2023              {
2024                  $localValue = &$value;
2025              }
2026  
2027              if (\is_array($dataType))
2028              {
2029                  $localDataType = array_shift($dataType);
2030              }
2031              else
2032              {
2033                  $localDataType = $dataType;
2034              }
2035  
2036              // Validate parameter type
2037              if (!isset($this->parameterMapping[$localDataType]))
2038              {
2039                  throw new \InvalidArgumentException(sprintf('Unsupported parameter type `%s`', $localDataType));
2040              }
2041  
2042              $obj                = new \stdClass;
2043              $obj->value         = &$localValue;
2044              $obj->dataType      = $this->parameterMapping[$localDataType];
2045              $obj->length        = $length;
2046              $obj->driverOptions = $driverOptions;
2047  
2048              // Add the Key/Value into the bounded array
2049              $this->bounded[$index] = $obj;
2050  
2051              unset($localValue);
2052          }
2053  
2054          return $this;
2055      }
2056  
2057      /**
2058       * Method to unbind a bound variable.
2059       *
2060       * @param   array|string|integer  $key  The key or array of keys to unbind.
2061       *
2062       * @return  $this
2063       *
2064       * @since   2.0.0
2065       */
2066  	public function unbind($key)
2067      {
2068          if (\is_array($key))
2069          {
2070              foreach ($key as $k)
2071              {
2072                  unset($this->bounded[$k]);
2073              }
2074          }
2075          else
2076          {
2077              unset($this->bounded[$key]);
2078          }
2079  
2080          return $this;
2081      }
2082  
2083      /**
2084       * Binds an array of values and returns an array of prepared parameter names.
2085       *
2086       * Note that all values must be the same data type.
2087       *
2088       * Usage:
2089       * $query->where('column in (' . implode(',', $query->bindArray($keyValues, $dataType)) . ')');
2090       *
2091       * @param   array         $values    Values to bind
2092       * @param   array|string  $dataType  Constant corresponding to a SQL datatype. It can be an array, in this case it
2093       *                                   has to be same length of $key
2094       *
2095       * @return  array   An array with parameter names
2096       *
2097       * @since 2.0.0
2098       */
2099  	public function bindArray(array $values, $dataType = ParameterType::INTEGER)
2100      {
2101          $parameterNames = [];
2102  
2103          for ($i = 0; $i < count($values); $i++)
2104          {
2105              $parameterNames[] = ':preparedArray' . (++$this->preparedIndex);
2106          }
2107  
2108          $this->bind($parameterNames, $values, $dataType);
2109  
2110          return $parameterNames;
2111      }
2112  
2113      /**
2114       * Method to provide basic copy support.
2115       *
2116       * Any object pushed into the data of this class should have its own __clone() implementation.
2117       * This method does not support copying objects in a multidimensional array.
2118       *
2119       * @return  void
2120       *
2121       * @since   1.0
2122       */
2123  	public function __clone()
2124      {
2125          foreach ($this as $k => $v)
2126          {
2127              if ($k === 'db')
2128              {
2129                  continue;
2130              }
2131  
2132              if (\is_object($v))
2133              {
2134                  $this->{$k} = clone $v;
2135              }
2136              elseif (\is_array($v))
2137              {
2138                  foreach ($v as $i => $element)
2139                  {
2140                      if (\is_object($element))
2141                      {
2142                          $this->{$k}[$i] = clone $element;
2143                      }
2144                  }
2145              }
2146          }
2147      }
2148  
2149      /**
2150       * Retrieves the bound parameters array when key is null and returns it by reference. If a key is provided then that item is
2151       * returned.
2152       *
2153       * @param   mixed  $key  The bounded variable key to retrieve.
2154       *
2155       * @return  mixed
2156       *
2157       * @since   1.5.0
2158       */
2159      public function &getBounded($key = null)
2160      {
2161          if (empty($key))
2162          {
2163              return $this->bounded;
2164          }
2165  
2166          if (isset($this->bounded[$key]))
2167          {
2168              return $this->bounded[$key];
2169          }
2170      }
2171  
2172      /**
2173       * Combine a select statement to the current query by one of the set operators.
2174       * Operators: UNION, UNION ALL, EXCEPT or INTERSECT.
2175       *
2176       * @param   string                $name   The name of the set operator with parentheses.
2177       * @param   DatabaseQuery|string  $query  The DatabaseQuery object or string.
2178       *
2179       * @return  $this
2180       *
2181       * @since   2.0.0
2182       */
2183  	protected function merge($name, $query)
2184      {
2185          $this->type = $this->type ?: 'select';
2186  
2187          $this->merge[] = new Query\QueryElement($name, $query);
2188  
2189          return $this;
2190      }
2191  
2192      /**
2193       * Add a query to UNION with the current query.
2194       *
2195       * Usage:
2196       * $query->union('SELECT name FROM  #__foo')
2197       * $query->union('SELECT name FROM  #__foo', true)
2198       *
2199       * @param   DatabaseQuery|string  $query     The DatabaseQuery object or string to union.
2200       * @param   boolean               $distinct  True to only return distinct rows from the union.
2201       *
2202       * @return  $this
2203       *
2204       * @since   1.0
2205       */
2206  	public function union($query, $distinct = true)
2207      {
2208          // Set up the name with parentheses, the DISTINCT flag is redundant
2209          return $this->merge($distinct ? 'UNION ()' : 'UNION ALL ()', $query);
2210      }
2211  
2212      /**
2213       * Add a query to UNION ALL with the current query.
2214       *
2215       * Usage:
2216       * $query->unionAll('SELECT name FROM  #__foo')
2217       *
2218       * @param   DatabaseQuery|string  $query     The DatabaseQuery object or string to union.
2219       *
2220       * @return  $this
2221       *
2222       * @see     union
2223       * @since   1.5.0
2224       */
2225  	public function unionAll($query)
2226      {
2227          return $this->union($query, false);
2228      }
2229  
2230      /**
2231       * Set a single query to the query set.
2232       * On this type of DatabaseQuery you can use union(), unionAll(), order() and setLimit()
2233       *
2234       * Usage:
2235       * $query->querySet($query2->select('name')->from('#__foo')->order('id DESC')->setLimit(1))
2236       *       ->unionAll($query3->select('name')->from('#__foo')->order('id')->setLimit(1))
2237       *       ->order('name')
2238       *       ->setLimit(1)
2239       *
2240       * @param   DatabaseQuery  $query  The DatabaseQuery object or string.
2241       *
2242       * @return  $this
2243       *
2244       * @since   2.0.0
2245       */
2246  	public function querySet($query)
2247      {
2248          $this->type = 'querySet';
2249  
2250          $this->querySet = $query;
2251  
2252          return $this;
2253      }
2254  
2255      /**
2256       * Create a DatabaseQuery object of type querySet from current query.
2257       *
2258       * Usage:
2259       * $query->select('name')->from('#__foo')->order('id DESC')->setLimit(1)
2260       *       ->toQuerySet()
2261       *       ->unionAll($query2->select('name')->from('#__foo')->order('id')->setLimit(1))
2262       *       ->order('name')
2263       *       ->setLimit(1)
2264       *
2265       * @return  DatabaseQuery  A new object of the DatabaseQuery.
2266       *
2267       * @since   2.0.0
2268       */
2269  	public function toQuerySet()
2270      {
2271          return (new static($this->db))->querySet($this);
2272      }
2273  
2274      /**
2275       * Find and replace sprintf-like tokens in a format string.
2276       * Each token takes one of the following forms:
2277       *     %%       - A literal percent character.
2278       *     %[t]     - Where [t] is a type specifier.
2279       *     %[n]$[x] - Where [n] is an argument specifier and [t] is a type specifier.
2280       *
2281       * Types:
2282       * a - Numeric: Replacement text is coerced to a numeric type but not quoted or escaped.
2283       * e - Escape: Replacement text is passed to $this->escape().
2284       * E - Escape (extra): Replacement text is passed to $this->escape() with true as the second argument.
2285       * n - Name Quote: Replacement text is passed to $this->quoteName().
2286       * q - Quote: Replacement text is passed to $this->quote().
2287       * Q - Quote (no escape): Replacement text is passed to $this->quote() with false as the second argument.
2288       * r - Raw: Replacement text is used as-is. (Be careful)
2289       *
2290       * Date Types:
2291       * - Replacement text automatically quoted (use uppercase for Name Quote).
2292       * - Replacement text should be a string in date format or name of a date column.
2293       * y/Y - Year
2294       * m/M - Month
2295       * d/D - Day
2296       * h/H - Hour
2297       * i/I - Minute
2298       * s/S - Second
2299       *
2300       * Invariable Types:
2301       * - Takes no argument.
2302       * - Argument index not incremented.
2303       * t - Replacement text is the result of $this->currentTimestamp().
2304       * z - Replacement text is the result of $this->nullDate(false).
2305       * Z - Replacement text is the result of $this->nullDate(true).
2306       *
2307       * Usage:
2308       * $query->format('SELECT %1$n FROM %2$n WHERE %3$n = %4$a', 'foo', '#__foo', 'bar', 1);
2309       * Returns: SELECT `foo` FROM `#__foo` WHERE `bar` = 1
2310       *
2311       * Notes:
2312       * The argument specifier is optional but recommended for clarity.
2313       * The argument index used for unspecified tokens is incremented only when used.
2314       *
2315       * @param   string  $format  The formatting string.
2316       *
2317       * @return  string  Returns a string produced according to the formatting string.
2318       *
2319       * @since   1.0
2320       */
2321  	public function format($format)
2322      {
2323          $query = $this;
2324          $args  = \array_slice(\func_get_args(), 1);
2325          array_unshift($args, null);
2326  
2327          $i    = 1;
2328          $func = function ($match) use ($query, $args, &$i)
2329          {
2330              if (isset($match[6]) && $match[6] === '%')
2331              {
2332                  return '%';
2333              }
2334  
2335              // No argument required, do not increment the argument index.
2336              switch ($match[5])
2337              {
2338                  case 't':
2339                      return $query->currentTimestamp();
2340  
2341                  case 'z':
2342                      return $query->nullDate(false);
2343  
2344                  case 'Z':
2345                      return $query->nullDate(true);
2346              }
2347  
2348              // Increment the argument index only if argument specifier not provided.
2349              $index = is_numeric($match[4]) ? (int) $match[4] : $i++;
2350  
2351              if (!$index || !isset($args[$index]))
2352              {
2353                  // TODO - What to do? sprintf() throws a Warning in these cases.
2354                  $replacement = '';
2355              }
2356              else
2357              {
2358                  $replacement = $args[$index];
2359              }
2360  
2361              switch ($match[5])
2362              {
2363                  case 'a':
2364                      return 0 + $replacement;
2365  
2366                  case 'e':
2367                      return $query->escape($replacement);
2368  
2369                  case 'E':
2370                      return $query->escape($replacement, true);
2371  
2372                  case 'n':
2373                      return $query->quoteName($replacement);
2374  
2375                  case 'q':
2376                      return $query->quote($replacement);
2377  
2378                  case 'Q':
2379                      return $query->quote($replacement, false);
2380  
2381                  case 'r':
2382                      return $replacement;
2383  
2384                  // Dates
2385                  case 'y':
2386                      return $query->year($query->quote($replacement));
2387  
2388                  case 'Y':
2389                      return $query->year($query->quoteName($replacement));
2390  
2391                  case 'm':
2392                      return $query->month($query->quote($replacement));
2393  
2394                  case 'M':
2395                      return $query->month($query->quoteName($replacement));
2396  
2397                  case 'd':
2398                      return $query->day($query->quote($replacement));
2399  
2400                  case 'D':
2401                      return $query->day($query->quoteName($replacement));
2402  
2403                  case 'h':
2404                      return $query->hour($query->quote($replacement));
2405  
2406                  case 'H':
2407                      return $query->hour($query->quoteName($replacement));
2408  
2409                  case 'i':
2410                      return $query->minute($query->quote($replacement));
2411  
2412                  case 'I':
2413                      return $query->minute($query->quoteName($replacement));
2414  
2415                  case 's':
2416                      return $query->second($query->quote($replacement));
2417  
2418                  case 'S':
2419                      return $query->second($query->quoteName($replacement));
2420              }
2421  
2422              return '';
2423          };
2424  
2425          /**
2426           * Regexp to find an replace all tokens.
2427           * Matched fields:
2428           * 0: Full token
2429           * 1: Everything following '%'
2430           * 2: Everything following '%' unless '%'
2431           * 3: Argument specifier and '$'
2432           * 4: Argument specifier
2433           * 5: Type specifier
2434           * 6: '%' if full token is '%%'
2435           */
2436          return preg_replace_callback('#%(((([\d]+)\$)?([aeEnqQryYmMdDhHiIsStzZ]))|(%))#', $func, $format);
2437      }
2438  
2439      /**
2440       * Validate arguments which are passed to selectRowNumber method and set up common variables.
2441       *
2442       * @param   string  $orderBy           An expression of ordering for window function.
2443       * @param   string  $orderColumnAlias  An alias for new ordering column.
2444       *
2445       * @return  void
2446       *
2447       * @since   2.0.0
2448       * @throws  \RuntimeException
2449       */
2450  	protected function validateRowNumber($orderBy, $orderColumnAlias)
2451      {
2452          if ($this->selectRowNumber)
2453          {
2454              throw new \RuntimeException("Method 'selectRowNumber' can be called only once per instance.");
2455          }
2456  
2457          $this->type = 'select';
2458  
2459          $this->selectRowNumber = [
2460              'orderBy'          => $orderBy,
2461              'orderColumnAlias' => $orderColumnAlias,
2462          ];
2463      }
2464  
2465      /**
2466       * Return the number of the current row.
2467       *
2468       * Usage:
2469       * $query->select('id');
2470       * $query->selectRowNumber('ordering,publish_up DESC', 'new_ordering');
2471       * $query->from('#__content');
2472       *
2473       * @param   string  $orderBy           An expression of ordering for window function.
2474       * @param   string  $orderColumnAlias  An alias for new ordering column.
2475       *
2476       * @return  $this
2477       *
2478       * @since   2.0.0
2479       * @throws  \RuntimeException
2480       */
2481  	public function selectRowNumber($orderBy, $orderColumnAlias)
2482      {
2483          $this->validateRowNumber($orderBy, $orderColumnAlias);
2484  
2485          return $this->select("ROW_NUMBER() OVER (ORDER BY $orderBy) AS $orderColumnAlias");
2486      }
2487  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer