[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/joomla/database/src/Sqlsrv/ -> SqlsrvDriver.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\Sqlsrv;
  10  
  11  use Joomla\Database\DatabaseDriver;
  12  use Joomla\Database\DatabaseEvents;
  13  use Joomla\Database\Event\ConnectionEvent;
  14  use Joomla\Database\Exception\ConnectionFailureException;
  15  use Joomla\Database\Exception\ExecutionFailureException;
  16  use Joomla\Database\Exception\PrepareStatementFailureException;
  17  use Joomla\Database\Exception\UnsupportedAdapterException;
  18  use Joomla\Database\StatementInterface;
  19  
  20  /**
  21   * SQL Server Database Driver
  22   *
  23   * @link   https://www.php.net/manual/en/book.sqlsrv.php
  24   * @since  1.0
  25   */
  26  class SqlsrvDriver extends DatabaseDriver
  27  {
  28      /**
  29       * The name of the database driver.
  30       *
  31       * @var    string
  32       * @since  1.0
  33       */
  34      public $name = 'sqlsrv';
  35  
  36      /**
  37       * The character(s) used to quote SQL statement names such as table names or field names, etc.
  38       *
  39       * If a single character string the same character is used for both sides of the quoted name, else the first character will be used for the
  40       * opening quote and the second for the closing quote.
  41       *
  42       * @var    string
  43       * @since  1.0
  44       */
  45      protected $nameQuote = '[]';
  46  
  47      /**
  48       * The null or zero representation of a timestamp for the database driver.
  49       *
  50       * @var    string
  51       * @since  1.0
  52       */
  53      protected $nullDate = '1900-01-01 00:00:00';
  54  
  55      /**
  56       * The minimum supported database version.
  57       *
  58       * @var    string
  59       * @since  1.0
  60       */
  61      protected static $dbMinimum = '11.0.2100.60';
  62  
  63      /**
  64       * Test to see if the SQLSRV connector is available.
  65       *
  66       * @return  boolean  True on success, false otherwise.
  67       *
  68       * @since   1.0
  69       */
  70  	public static function isSupported()
  71      {
  72          return \function_exists('sqlsrv_connect');
  73      }
  74  
  75      /**
  76       * Constructor.
  77       *
  78       * @param   array  $options  List of options used to configure the connection
  79       *
  80       * @since   1.0
  81       */
  82  	public function __construct(array $options)
  83      {
  84          // Get some basic values from the options.
  85          $options['host']     = $options['host'] ?? 'localhost';
  86          $options['user']     = $options['user'] ?? '';
  87          $options['password'] = $options['password'] ?? '';
  88          $options['database'] = $options['database'] ?? '';
  89          $options['select']   = isset($options['select']) ? (bool) $options['select'] : true;
  90  
  91          // Finalize initialisation
  92          parent::__construct($options);
  93      }
  94  
  95      /**
  96       * Connects to the database if needed.
  97       *
  98       * @return  void  Returns void if the database connected successfully.
  99       *
 100       * @since   1.0
 101       * @throws  \RuntimeException
 102       */
 103  	public function connect()
 104      {
 105          if ($this->connection)
 106          {
 107              return;
 108          }
 109  
 110          // Make sure the SQLSRV extension for PHP is installed and enabled.
 111          if (!static::isSupported())
 112          {
 113              throw new UnsupportedAdapterException('PHP extension sqlsrv_connect is not available.');
 114          }
 115  
 116          // Build the connection configuration array.
 117          $config = [
 118              'Database'             => $this->options['database'],
 119              'uid'                  => $this->options['user'],
 120              'pwd'                  => $this->options['password'],
 121              'CharacterSet'         => 'UTF-8',
 122              'ReturnDatesAsStrings' => true,
 123          ];
 124  
 125          // Attempt to connect to the server.
 126          if (!($this->connection = @ sqlsrv_connect($this->options['host'], $config)))
 127          {
 128              throw new ConnectionFailureException('Could not connect to SQL Server');
 129          }
 130  
 131          // Make sure that DB warnings are not returned as errors.
 132          sqlsrv_configure('WarningsReturnAsErrors', 0);
 133  
 134          // If auto-select is enabled select the given database.
 135          if ($this->options['select'] && !empty($this->options['database']))
 136          {
 137              $this->select($this->options['database']);
 138          }
 139  
 140          $this->dispatchEvent(new ConnectionEvent(DatabaseEvents::POST_CONNECT, $this));
 141      }
 142  
 143      /**
 144       * Disconnects the database.
 145       *
 146       * @return  void
 147       *
 148       * @since   1.0
 149       */
 150  	public function disconnect()
 151      {
 152          // Close the connection.
 153          if (\is_resource($this->connection))
 154          {
 155              sqlsrv_close($this->connection);
 156          }
 157  
 158          parent::disconnect();
 159      }
 160  
 161      /**
 162       * Get table constraints
 163       *
 164       * @param   string  $tableName  The name of the database table.
 165       *
 166       * @return  array  Any constraints available for the table.
 167       *
 168       * @since   1.0
 169       */
 170  	protected function getTableConstraints($tableName)
 171      {
 172          $this->connect();
 173  
 174          return $this->setQuery('SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = ' . $this->quote($tableName))
 175              ->loadColumn();
 176      }
 177  
 178      /**
 179       * Rename constraints.
 180       *
 181       * @param   array   $constraints  Array(strings) of table constraints
 182       * @param   string  $prefix       A string
 183       * @param   string  $backup       A string
 184       *
 185       * @return  void
 186       *
 187       * @since   1.0
 188       */
 189  	protected function renameConstraints($constraints = [], $prefix = null, $backup = null)
 190      {
 191          $this->connect();
 192  
 193          foreach ($constraints as $constraint)
 194          {
 195              $this->setQuery('sp_rename ' . $constraint . ',' . str_replace($prefix, $backup, $constraint))
 196                  ->execute();
 197          }
 198      }
 199  
 200      /**
 201       * Method to escape a string for usage in an SQL statement.
 202       *
 203       * The escaping for MSSQL isn't handled in the driver though that would be nice.  Because of this we need to handle the escaping ourselves.
 204       *
 205       * @param   string   $text   The string to be escaped.
 206       * @param   boolean  $extra  Optional parameter to provide extra escaping.
 207       *
 208       * @return  string  The escaped string.
 209       *
 210       * @since   1.0
 211       */
 212  	public function escape($text, $extra = false)
 213      {
 214          if (\is_int($text))
 215          {
 216              return $text;
 217          }
 218  
 219          if (\is_float($text))
 220          {
 221              // Force the dot as a decimal point.
 222              return str_replace(',', '.', $text);
 223          }
 224  
 225          $result = str_replace("'", "''", $text);
 226  
 227          // SQL Server does not accept NULL byte in query string
 228          $result = str_replace("\0", "' + CHAR(0) + N'", $result);
 229  
 230          // Fix for SQL Sever escape sequence, see https://support.microsoft.com/en-us/kb/164291
 231          $result = str_replace(
 232              ["\\\n",     "\\\r",     "\\\\\r\r\n"],
 233              ["\\\\\n\n", "\\\\\r\r", "\\\\\r\n\r\n"],
 234              $result
 235          );
 236  
 237          if ($extra)
 238          {
 239              // Escape special chars
 240              $result = str_replace(
 241                  ['[',   '_',   '%'],
 242                  ['[[]', '[_]', '[%]'],
 243                  $result
 244              );
 245          }
 246  
 247          return $result;
 248      }
 249  
 250      /**
 251       * Quotes and optionally escapes a string to database requirements for use in database queries.
 252       *
 253       * @param   mixed    $text    A string or an array of strings to quote.
 254       * @param   boolean  $escape  True (default) to escape the string, false to leave it unchanged.
 255       *
 256       * @return  string  The quoted input string.
 257       *
 258       * @since   1.6.0
 259       */
 260  	public function quote($text, $escape = true)
 261      {
 262          if (\is_array($text))
 263          {
 264              return parent::quote($text, $escape);
 265          }
 266  
 267          // To support unicode on MSSQL we have to add prefix N
 268          return 'N\'' . ($escape ? $this->escape($text) : $text) . '\'';
 269      }
 270  
 271      /**
 272       * Quotes a binary string to database requirements for use in database queries.
 273       *
 274       * @param   string  $data  A binary string to quote.
 275       *
 276       * @return  string  The binary quoted input string.
 277       *
 278       * @since   1.7.0
 279       */
 280  	public function quoteBinary($data)
 281      {
 282          // ODBC syntax for hexadecimal literals
 283          return '0x' . bin2hex($data);
 284      }
 285  
 286      /**
 287       * Determines if the connection to the server is active.
 288       *
 289       * @return  boolean  True if connected to the database engine.
 290       *
 291       * @since   1.0
 292       */
 293  	public function connected()
 294      {
 295          // TODO: Run a blank query here
 296          return true;
 297      }
 298  
 299      /**
 300       * Drops a table from the database.
 301       *
 302       * @param   string   $table     The name of the database table to drop.
 303       * @param   boolean  $ifExists  Optionally specify that the table must exist before it is dropped.
 304       *
 305       * @return  $this
 306       *
 307       * @since   1.0
 308       */
 309  	public function dropTable($table, $ifExists = true)
 310      {
 311          $this->connect();
 312  
 313          if ($ifExists)
 314          {
 315              $this->setQuery(
 316                  'IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '
 317                      . $this->quote($table) . ') DROP TABLE ' . $table
 318              );
 319          }
 320          else
 321          {
 322              $this->setQuery('DROP TABLE ' . $table);
 323          }
 324  
 325          $this->execute();
 326  
 327          return $this;
 328      }
 329  
 330      /**
 331       * Method to get the database collation in use by sampling a text field of a table in the database.
 332       *
 333       * @return  string|boolean  The collation in use by the database or boolean false if not supported.
 334       *
 335       * @since   1.0
 336       */
 337  	public function getCollation()
 338      {
 339          // TODO: Not fake this
 340          return 'MSSQL UTF-8 (UCS2)';
 341      }
 342  
 343      /**
 344       * Method to get the database connection collation in use by sampling a text field of a table in the database.
 345       *
 346       * @return  string|boolean  The collation in use by the database connection (string) or boolean false if not supported.
 347       *
 348       * @since   1.6.0
 349       * @throws  \RuntimeException
 350       */
 351  	public function getConnectionCollation()
 352      {
 353          // TODO: Not fake this
 354          return 'MSSQL UTF-8 (UCS2)';
 355      }
 356  
 357      /**
 358       * Method to get the database encryption details (cipher and protocol) in use.
 359       *
 360       * @return  string  The database encryption details.
 361       *
 362       * @since   2.0.0
 363       * @throws  \RuntimeException
 364       */
 365  	public function getConnectionEncryption(): string
 366      {
 367          // TODO: Not fake this
 368          return '';
 369      }
 370  
 371      /**
 372       * Method to test if the database TLS connections encryption are supported.
 373       *
 374       * @return  boolean  Whether the database supports TLS connections encryption.
 375       *
 376       * @since   2.0.0
 377       */
 378  	public function isConnectionEncryptionSupported(): bool
 379      {
 380          // TODO: Not fake this
 381          return false;
 382      }
 383  
 384      /**
 385       * Retrieves field information about the given tables.
 386       *
 387       * @param   mixed    $table     A table name
 388       * @param   boolean  $typeOnly  True to only return field types.
 389       *
 390       * @return  array  An array of fields.
 391       *
 392       * @since   1.0
 393       * @throws  \RuntimeException
 394       */
 395  	public function getTableColumns($table, $typeOnly = true)
 396      {
 397          $result = [];
 398  
 399          $table_temp = $this->replacePrefix((string) $table);
 400  
 401          // Set the query to get the table fields statement.
 402          $this->setQuery(
 403              'SELECT column_name as Field, data_type as Type, is_nullable as \'Null\', column_default as \'Default\'' .
 404              ' FROM information_schema.columns WHERE table_name = ' . $this->quote($table_temp)
 405          );
 406          $fields = $this->loadObjectList();
 407  
 408          // If we only want the type as the value add just that to the list.
 409          if ($typeOnly)
 410          {
 411              foreach ($fields as $field)
 412              {
 413                  $result[$field->Field] = preg_replace('/[(0-9)]/', '', $field->Type);
 414              }
 415          }
 416          else
 417          {
 418              // If we want the whole field data object add that to the list.
 419              foreach ($fields as $field)
 420              {
 421                  $field->Default        = preg_replace("/(^(\(\(|\('|\(N'|\()|(('\)|(?<!\()\)\)|\))$))/i", '', $field->Default);
 422                  $result[$field->Field] = $field;
 423              }
 424          }
 425  
 426          return $result;
 427      }
 428  
 429      /**
 430       * Shows the table CREATE statement that creates the given tables.
 431       *
 432       * This is unsupported by MSSQL.
 433       *
 434       * @param   mixed  $tables  A table name or a list of table names.
 435       *
 436       * @return  array  A list of the create SQL for the tables.
 437       *
 438       * @since   1.0
 439       * @throws  \RuntimeException
 440       */
 441  	public function getTableCreate($tables)
 442      {
 443          $this->connect();
 444  
 445          return '';
 446      }
 447  
 448      /**
 449       * Get the details list of keys for a table.
 450       *
 451       * @param   string  $table  The name of the table.
 452       *
 453       * @return  array  An array of the column specification for the table.
 454       *
 455       * @since   1.0
 456       * @throws  \RuntimeException
 457       */
 458  	public function getTableKeys($table)
 459      {
 460          $this->connect();
 461  
 462          // TODO To implement.
 463          return [];
 464      }
 465  
 466      /**
 467       * Method to get an array of all tables in the database.
 468       *
 469       * @return  array  An array of all the tables in the database.
 470       *
 471       * @since   1.0
 472       * @throws  \RuntimeException
 473       */
 474  	public function getTableList()
 475      {
 476          $this->connect();
 477  
 478          // Set the query to get the tables statement.
 479          return $this->setQuery('SELECT name FROM ' . $this->getDatabase() . '.sys.Tables WHERE type = \'U\';')->loadColumn();
 480      }
 481  
 482      /**
 483       * Get the version of the database connector.
 484       *
 485       * @return  string  The database connector version.
 486       *
 487       * @since   1.0
 488       */
 489  	public function getVersion()
 490      {
 491          $this->connect();
 492  
 493          $version = sqlsrv_server_info($this->connection);
 494  
 495          return $version['SQLServerVersion'];
 496      }
 497  
 498      /**
 499       * Inserts a row into a table based on an object's properties.
 500       *
 501       * @param   string  $table   The name of the database table to insert into.
 502       * @param   object  $object  A reference to an object whose public properties match the table fields.
 503       * @param   string  $key     The name of the primary key. If provided the object property is updated.
 504       *
 505       * @return  boolean  True on success.
 506       *
 507       * @since   1.0
 508       * @throws  \RuntimeException
 509       */
 510  	public function insertObject($table, &$object, $key = null)
 511      {
 512          $fields       = [];
 513          $values       = [];
 514          $tableColumns = $this->getTableColumns($table);
 515          $statement    = 'INSERT INTO ' . $this->quoteName($table) . ' (%s) VALUES (%s)';
 516  
 517          foreach (get_object_vars($object) as $k => $v)
 518          {
 519              // Skip columns that don't exist in the table.
 520              if (!\array_key_exists($k, $tableColumns))
 521              {
 522                  continue;
 523              }
 524  
 525              // Only process non-null scalars.
 526              if (\is_array($v) || \is_object($v) || $v === null)
 527              {
 528                  continue;
 529              }
 530  
 531              if (!$this->checkFieldExists($table, $k))
 532              {
 533                  continue;
 534              }
 535  
 536              if ($k[0] === '_')
 537              {
 538                  // Internal field
 539                  continue;
 540              }
 541  
 542              if ($k === $key && $key == 0)
 543              {
 544                  continue;
 545              }
 546  
 547              $fields[] = $this->quoteName($k);
 548              $values[] = $this->quote($v);
 549          }
 550  
 551          // Set the query and execute the insert.
 552          $this->setQuery(sprintf($statement, implode(',', $fields), implode(',', $values)))->execute();
 553  
 554          $id = $this->insertid();
 555  
 556          if ($key && $id)
 557          {
 558              $object->$key = $id;
 559          }
 560  
 561          return true;
 562      }
 563  
 564      /**
 565       * Method to get the auto-incremented value from the last INSERT statement.
 566       *
 567       * @return  integer  The value of the auto-increment field from the last inserted row.
 568       *
 569       * @since   1.0
 570       */
 571  	public function insertid()
 572      {
 573          $this->connect();
 574  
 575          // TODO: SELECT IDENTITY
 576          $this->setQuery('SELECT @@IDENTITY');
 577  
 578          return (int) $this->loadResult();
 579      }
 580  
 581      /**
 582       * Execute the SQL statement.
 583       *
 584       * @return  boolean
 585       *
 586       * @since   1.0
 587       * @throws  \RuntimeException
 588       */
 589  	public function execute()
 590      {
 591          $this->connect();
 592  
 593          // Take a local copy so that we don't modify the original query and cause issues later
 594          $sql = $this->replacePrefix((string) $this->sql);
 595  
 596          // Increment the query counter.
 597          $this->count++;
 598  
 599          // Get list of bounded parameters
 600          $bounded =& $this->sql->getBounded();
 601  
 602          // If there is a monitor registered, let it know we are starting this query
 603          if ($this->monitor)
 604          {
 605              $this->monitor->startQuery($sql, $bounded);
 606          }
 607  
 608          // Execute the query.
 609          $this->executed = false;
 610  
 611          // Bind the variables
 612          foreach ($bounded as $key => $obj)
 613          {
 614              $this->statement->bindParam($key, $obj->value, $obj->dataType);
 615          }
 616  
 617          try
 618          {
 619              $this->executed = $this->statement->execute();
 620  
 621              // If there is a monitor registered, let it know we have finished this query
 622              if ($this->monitor)
 623              {
 624                  $this->monitor->stopQuery();
 625              }
 626  
 627              return true;
 628          }
 629          catch (ExecutionFailureException $exception)
 630          {
 631              // If there is a monitor registered, let it know we have finished this query
 632              if ($this->monitor)
 633              {
 634                  $this->monitor->stopQuery();
 635              }
 636  
 637              // Check if the server was disconnected.
 638              if (!$this->connected())
 639              {
 640                  try
 641                  {
 642                      // Attempt to reconnect.
 643                      $this->connection = null;
 644                      $this->connect();
 645                  }
 646                  catch (ConnectionFailureException $e)
 647                  {
 648                      // If connect fails, ignore that exception and throw the normal exception.
 649                      throw $exception;
 650                  }
 651  
 652                  // Since we were able to reconnect, run the query again.
 653                  return $this->execute();
 654              }
 655  
 656              // Throw the normal query exception.
 657              throw $exception;
 658          }
 659      }
 660  
 661      /**
 662       * This function replaces a string identifier with the configured table prefix.
 663       *
 664       * @param   string  $sql     The SQL statement to prepare.
 665       * @param   string  $prefix  The table prefix.
 666       *
 667       * @return  string  The processed SQL statement.
 668       *
 669       * @since   1.0
 670       */
 671  	public function replacePrefix($sql, $prefix = '#__')
 672      {
 673          $escaped   = false;
 674          $startPos  = 0;
 675          $quoteChar = '';
 676          $literal   = '';
 677  
 678          $sql = trim($sql);
 679          $n   = \strlen($sql);
 680  
 681          while ($startPos < $n)
 682          {
 683              $ip = strpos($sql, $prefix, $startPos);
 684  
 685              if ($ip === false)
 686              {
 687                  break;
 688              }
 689  
 690              $j = strpos($sql, "N'", $startPos);
 691              $k = strpos($sql, '"', $startPos);
 692  
 693              if (($k !== false) && (($k < $j) || ($j === false)))
 694              {
 695                  $quoteChar = '"';
 696                  $j         = $k;
 697              }
 698              else
 699              {
 700                  $quoteChar = "'";
 701              }
 702  
 703              if ($j === false)
 704              {
 705                  $j = $n;
 706              }
 707  
 708              $literal .= str_replace($prefix, $this->tablePrefix, substr($sql, $startPos, $j - $startPos));
 709              $startPos = $j;
 710  
 711              $j = $startPos + 1;
 712  
 713              if ($j >= $n)
 714              {
 715                  break;
 716              }
 717  
 718              // Quote comes first, find end of quote
 719              while (true)
 720              {
 721                  $k       = strpos($sql, $quoteChar, $j);
 722                  $escaped = false;
 723  
 724                  if ($k === false)
 725                  {
 726                      break;
 727                  }
 728  
 729                  $l = $k - 1;
 730  
 731                  while ($l >= 0 && $sql[$l] === '\\')
 732                  {
 733                      $l--;
 734                      $escaped = !$escaped;
 735                  }
 736  
 737                  if ($escaped)
 738                  {
 739                      $j = $k + 1;
 740  
 741                      continue;
 742                  }
 743  
 744                  break;
 745              }
 746  
 747              if ($k === false)
 748              {
 749                  // Error in the query - no end quote; ignore it
 750                  break;
 751              }
 752  
 753              $literal .= substr($sql, $startPos, $k - $startPos + 1);
 754              $startPos = $k + 1;
 755          }
 756  
 757          if ($startPos < $n)
 758          {
 759              $literal .= substr($sql, $startPos, $n - $startPos);
 760          }
 761  
 762          return $literal;
 763      }
 764  
 765      /**
 766       * Select a database for use.
 767       *
 768       * @param   string  $database  The name of the database to select for use.
 769       *
 770       * @return  boolean  True if the database was successfully selected.
 771       *
 772       * @since   1.0
 773       * @throws  ConnectionFailureException
 774       */
 775  	public function select($database)
 776      {
 777          $this->connect();
 778  
 779          if (!$database)
 780          {
 781              return false;
 782          }
 783  
 784          if (!sqlsrv_query($this->connection, 'USE [' . $database . ']', null, ['scrollable' => \SQLSRV_CURSOR_STATIC]))
 785          {
 786              throw new ConnectionFailureException('Could not connect to database');
 787          }
 788  
 789          return true;
 790      }
 791  
 792      /**
 793       * Set the connection to use UTF-8 character encoding.
 794       *
 795       * @return  boolean  True on success.
 796       *
 797       * @since   1.0
 798       */
 799  	public function setUtf()
 800      {
 801          return true;
 802      }
 803  
 804      /**
 805       * Method to commit a transaction.
 806       *
 807       * @param   boolean  $toSavepoint  If true, commit to the last savepoint.
 808       *
 809       * @return  void
 810       *
 811       * @since   1.0
 812       * @throws  \RuntimeException
 813       */
 814  	public function transactionCommit($toSavepoint = false)
 815      {
 816          $this->connect();
 817  
 818          if (!$toSavepoint || $this->transactionDepth <= 1)
 819          {
 820              $this->setQuery('COMMIT TRANSACTION')->execute();
 821  
 822              $this->transactionDepth = 0;
 823  
 824              return;
 825          }
 826  
 827          $this->transactionDepth--;
 828      }
 829  
 830      /**
 831       * Method to roll back a transaction.
 832       *
 833       * @param   boolean  $toSavepoint  If true, rollback to the last savepoint.
 834       *
 835       * @return  void
 836       *
 837       * @since   1.0
 838       * @throws  \RuntimeException
 839       */
 840  	public function transactionRollback($toSavepoint = false)
 841      {
 842          $this->connect();
 843  
 844          if (!$toSavepoint || $this->transactionDepth <= 1)
 845          {
 846              $this->setQuery('ROLLBACK TRANSACTION')->execute();
 847  
 848              $this->transactionDepth = 0;
 849  
 850              return;
 851          }
 852  
 853          $savepoint = 'SP_' . ($this->transactionDepth - 1);
 854          $this->setQuery('ROLLBACK TRANSACTION ' . $this->quoteName($savepoint))->execute();
 855  
 856          $this->transactionDepth--;
 857      }
 858  
 859      /**
 860       * Method to initialize a transaction.
 861       *
 862       * @param   boolean  $asSavepoint  If true and a transaction is already active, a savepoint will be created.
 863       *
 864       * @return  void
 865       *
 866       * @since   1.0
 867       * @throws  \RuntimeException
 868       */
 869  	public function transactionStart($asSavepoint = false)
 870      {
 871          $this->connect();
 872  
 873          if (!$asSavepoint || !$this->transactionDepth)
 874          {
 875              $this->setQuery('BEGIN TRANSACTION')->execute();
 876  
 877              $this->transactionDepth = 1;
 878  
 879              return;
 880          }
 881  
 882          $savepoint = 'SP_' . $this->transactionDepth;
 883          $this->setQuery('BEGIN TRANSACTION ' . $this->quoteName($savepoint))->execute();
 884  
 885          $this->transactionDepth++;
 886      }
 887  
 888      /**
 889       * Method to check and see if a field exists in a table.
 890       *
 891       * @param   string  $table  The table in which to verify the field.
 892       * @param   string  $field  The field to verify.
 893       *
 894       * @return  boolean  True if the field exists in the table.
 895       *
 896       * @since   1.0
 897       */
 898  	protected function checkFieldExists($table, $field)
 899      {
 900          $this->connect();
 901  
 902          $table = $this->replacePrefix((string) $table);
 903          $this->setQuery(
 904              "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '$table' AND COLUMN_NAME = '$field' ORDER BY ORDINAL_POSITION"
 905          );
 906  
 907          return (bool) $this->loadResult();
 908      }
 909  
 910      /**
 911       * Prepares a SQL statement for execution
 912       *
 913       * @param   string  $query  The SQL query to be prepared.
 914       *
 915       * @return  StatementInterface
 916       *
 917       * @since   2.0.0
 918       * @throws  PrepareStatementFailureException
 919       */
 920  	protected function prepareStatement(string $query): StatementInterface
 921      {
 922          return new SqlsrvStatement($this->connection, $query);
 923      }
 924  
 925      /**
 926       * Renames a table in the database.
 927       *
 928       * @param   string  $oldTable  The name of the table to be renamed
 929       * @param   string  $newTable  The new name for the table.
 930       * @param   string  $backup    Table prefix
 931       * @param   string  $prefix    For the table - used to rename constraints in non-mysql databases
 932       *
 933       * @return  $this
 934       *
 935       * @since   1.0
 936       * @throws  \RuntimeException
 937       */
 938  	public function renameTable($oldTable, $newTable, $backup = null, $prefix = null)
 939      {
 940          $constraints = [];
 941  
 942          if ($prefix !== null && $backup !== null)
 943          {
 944              $constraints = $this->getTableConstraints($oldTable);
 945          }
 946  
 947          if (!empty($constraints))
 948          {
 949              $this->renameConstraints($constraints, $prefix, $backup);
 950          }
 951  
 952          $this->setQuery("sp_rename '" . $oldTable . "', '" . $newTable . "'");
 953  
 954          $this->execute();
 955  
 956          return $this;
 957      }
 958  
 959      /**
 960       * Locks a table in the database.
 961       *
 962       * @param   string  $tableName  The name of the table to lock.
 963       *
 964       * @return  $this
 965       *
 966       * @since   1.0
 967       * @throws  \RuntimeException
 968       */
 969  	public function lockTable($tableName)
 970      {
 971          return $this;
 972      }
 973  
 974      /**
 975       * Unlocks tables in the database.
 976       *
 977       * @return  $this
 978       *
 979       * @since   1.0
 980       * @throws  \RuntimeException
 981       */
 982  	public function unlockTables()
 983      {
 984          return $this;
 985      }
 986  }


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