1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
connection.php
См. документацию.
1<?php
2
3namespace Bitrix\Main\DB;
4
5use Bitrix\Main;
6use Bitrix\Main\ArgumentNullException;
7use Bitrix\Main\Data;
8use Bitrix\Main\Diag;
9use Bitrix\Main\ORM\Fields\ScalarField;
10
17abstract class Connection extends Data\Connection
18{
19 const PERSISTENT = 1;
20 const DEFERRED = 2;
21 const INDEX_UNIQUE = 'UNIQUE';
22 const INDEX_FULLTEXT = 'FULLTEXT';
23 const INDEX_SPATIAL = 'SPATIAL';
24
26 protected $sqlHelper;
28 protected $sqlTracker;
29 protected $trackSql = false;
30 protected $version;
31 protected $versionExpress;
32 protected $host;
33 protected $database;
34 protected $login;
35 protected $password;
36 protected $initCommand = 0;
37 protected $options = 0;
38 protected $nodeId = 0;
39 protected $utf8mb4 = [];
40 protected $tableColumnsCache = [];
46 protected $queryExecutingEnabled = true;
49
64 {
65 parent::__construct($configuration);
66
67 $this->host = $configuration['host'] ?? '';
68 $this->database = $configuration['database'] ?? '';
69 $this->login = $configuration['login'] ?? '';
70 $this->password = $configuration['password'] ?? '';
71 $this->initCommand = $configuration['initCommand'] ?? '';
72 $this->options = intval($configuration['options'] ?? 2);
73 $this->utf8mb4 = (isset($configuration['utf8mb4']) && is_array($configuration['utf8mb4']) ? $configuration['utf8mb4'] : []);
74 }
75
80 public function getDbName()
81 {
82 return $this->getDatabase();
83 }
84
90 public function getHost()
91 {
92 return $this->host;
93 }
94
100 public function getLogin()
101 {
102 return $this->login;
103 }
104
110 public function getPassword()
111 {
112 return $this->password;
113 }
114
120 public function getDatabase()
121 {
122 return $this->database;
123 }
124
134 public function disableQueryExecuting()
135 {
136 $this->queryExecutingEnabled = false;
137 }
138
147 public function enableQueryExecuting()
148 {
149 $this->queryExecutingEnabled = true;
150 }
151
158 public function isQueryExecutingEnabled()
159 {
160 return $this->queryExecutingEnabled;
161 }
162
172 {
173 $dump = $this->disabledQueryExecutingDump;
174 $this->disabledQueryExecutingDump = null;
175
176 return $dump;
177 }
178
179 /**********************************************************
180 * SqlHelper
181 **********************************************************/
182
183 abstract protected function createSqlHelper();
184
191 public function getSqlHelper()
192 {
193 if ($this->sqlHelper == null)
194 {
195 $this->sqlHelper = $this->createSqlHelper();
196 }
197
198 return $this->sqlHelper;
199 }
200
201 /***********************************************************
202 * Connection and disconnection
203 ***********************************************************/
204
210 public function connect()
211 {
212 $this->isConnected = false;
213
214 if (!$this->isDeferred())
215 {
216 parent::connect();
217 }
218 }
219
225 public function disconnect()
226 {
227 if (!$this->isPersistent())
228 {
229 parent::disconnect();
230 }
231 }
232
237 public function isDeferred()
238 {
239 return (($this->options & self::DEFERRED) !== 0);
240 }
241
246 public function isPersistent()
247 {
248 return (($this->options & self::PERSISTENT) !== 0);
249 }
250
251 /*********************************************************
252 * Query
253 *********************************************************/
254
269 abstract protected function queryInternal($sql, array $binds = null, Diag\SqlTrackerQuery $trackerQuery = null);
270
279 abstract protected function createResult($result, Diag\SqlTrackerQuery $trackerQuery = null);
280
299 public function query($sql)
300 {
301 [$sql, $binds, $offset, $limit] = self::parseQueryFunctionArgs(func_get_args());
302
303 if ($limit > 0)
304 {
305 $sql = $this->getSqlHelper()->getTopSql($sql, $limit, $offset);
306 }
307
308 $trackerQuery = null;
309
310 if ($this->queryExecutingEnabled)
311 {
312 $connection = Main\Application::getInstance()->getConnectionPool()->getSlaveConnection($sql);
313 if ($connection === null)
314 {
315 $connection = $this;
316 }
317
318 if ($this->trackSql)
319 {
320 $trackerQuery = $this->sqlTracker->getNewTrackerQuery();
321 $trackerQuery->setNode($connection->getNodeId());
322 }
323
324 $result = $connection->queryInternal($sql, $binds, $trackerQuery);
325 }
326 else
327 {
328 if ($this->disabledQueryExecutingDump === null)
329 {
330 $this->disabledQueryExecutingDump = [];
331 }
332
333 $this->disabledQueryExecutingDump[] = $sql;
334 $result = true;
335 }
336
337 return $this->createResult($result, $trackerQuery);
338 }
339
350 public function queryScalar($sql, array $binds = null)
351 {
352 $result = $this->query($sql, $binds, 0, 1);
353
354 if ($row = $result->fetch())
355 {
356 return array_shift($row);
357 }
358
359 return null;
360 }
361
371 public function queryExecute($sql, array $binds = null)
372 {
373 $this->query($sql, $binds);
374 }
375
384 protected static function parseQueryFunctionArgs($args)
385 {
386 /*
387 * query($sql)
388 * query($sql, $limit)
389 * query($sql, $offset, $limit)
390 * query($sql, $arBinds)
391 * query($sql, $arBinds, $limit)
392 * query($sql, $arBinds, $offset, $limit)
393 */
394 $numArgs = count($args);
395 if ($numArgs < 1)
396 {
397 throw new ArgumentNullException("sql");
398 }
399
400 $binds = [];
401 $offset = 0;
402 $limit = 0;
403
404 if ($numArgs == 1)
405 {
406 $sql = $args[0];
407 }
408 elseif ($numArgs == 2)
409 {
410 if (is_array($args[1]))
411 {
412 [$sql, $binds] = $args;
413 }
414 else
415 {
416 [$sql, $limit] = $args;
417 }
418 }
419 elseif ($numArgs == 3)
420 {
421 if (is_array($args[1]))
422 {
423 [$sql, $binds, $limit] = $args;
424 }
425 else
426 {
427 [$sql, $offset, $limit] = $args;
428 }
429 }
430 else
431 {
432 [$sql, $binds, $offset, $limit] = $args;
433 }
434
435 return [$sql, $binds, $offset, $limit];
436 }
437
450 public function add($tableName, array $data, $identity = "ID")
451 {
452 $insert = $this->getSqlHelper()->prepareInsert($tableName, $data);
453
454 $sql =
455 "INSERT INTO " . $this->getSqlHelper()->quote($tableName) . "(" . $insert[0] . ") " .
456 "VALUES (" . $insert[1] . ")";
457
458 $this->queryExecute($sql);
459
460 return $this->getInsertedId();
461 }
462
471 public function addMulti($tableName, $rows, $identity = "ID")
472 {
473 $uniqueColumns = [];
474 $inserts = [];
475
476 // prepare data
477 foreach ($rows as $data)
478 {
479 $insert = $this->getSqlHelper()->prepareInsert($tableName, $data, true);
480 $inserts[] = $insert;
481
482 // and get unique column names
483 foreach ($insert[0] as $column)
484 {
485 $uniqueColumns[$column] = true;
486 }
487 }
488
489 // prepare sql
490 $sqlValues = [];
491
492 foreach ($inserts as $insert)
493 {
494 $columns = array_flip($insert[0]);
495 $values = $insert[1];
496
497 $finalValues = [];
498
499 foreach (array_keys($uniqueColumns) as $column)
500 {
501 if (array_key_exists($column, $columns))
502 {
503 // set real value
504 $finalValues[] = $values[$columns[$column]];
505 }
506 else
507 {
508 // set default
509 $finalValues[] = 'DEFAULT';
510 }
511 }
512
513 $sqlValues[] = '(' . join(', ', $finalValues) . ')';
514 }
515
516 $sql = "INSERT INTO {$this->getSqlHelper()->quote($tableName)} (" . join(', ', array_keys($uniqueColumns)) . ") " .
517 "VALUES " . join(', ', $sqlValues);
518
519 $this->queryExecute($sql);
520
521 return $this->getInsertedId();
522 }
523
527 abstract public function getInsertedId();
528
538 public function executeSqlBatch($sqlBatch, $stopOnError = false)
539 {
540 $result = [];
541 foreach ($this->parseSqlBatch($sqlBatch) as $sql)
542 {
543 try
544 {
545 $this->queryExecute($sql);
546 }
547 catch (SqlException $ex)
548 {
549 $result[] = $ex->getMessage();
550 if ($stopOnError)
551 {
552 return $result;
553 }
554 }
555 }
556
557 return $result;
558 }
559
566 public function parseSqlBatch($sqlBatch)
567 {
568 $delimiter = $this->getSqlHelper()->getQueryDelimiter();
569
570 $sqlBatch = trim($sqlBatch);
571
572 $statements = [];
573 $sql = "";
574
575 do
576 {
577 if (preg_match("%^(.*?)(['\"`#]|--|\\$\\$|" . $delimiter . ")%is", $sqlBatch, $match))
578 {
579 //Found string start
580 if ($match[2] == "\"" || $match[2] == "'" || $match[2] == "`")
581 {
582 $sqlBatch = mb_substr($sqlBatch, mb_strlen($match[0]));
583 $sql .= $match[0];
584 //find a quote not preceded by \
585 if (preg_match("%^(.*?)(?<!\\\\‍)" . $match[2] . "%s", $sqlBatch, $stringMatch))
586 {
587 $sqlBatch = mb_substr($sqlBatch, mb_strlen($stringMatch[0]));
588 $sql .= $stringMatch[0];
589 }
590 else
591 {
592 //String foll beyond end of file
593 $sql .= $sqlBatch;
594 $sqlBatch = "";
595 }
596 }
597 //Comment found
598 elseif ($match[2] == "#" || $match[2] == "--")
599 {
600 //Take that was before comment as part of sql
601 $sqlBatch = mb_substr($sqlBatch, mb_strlen($match[1]));
602 $sql .= $match[1];
603 //And cut the rest
604 $p = mb_strpos($sqlBatch, "\n");
605 if ($p === false)
606 {
607 $p1 = mb_strpos($sqlBatch, "\r");
608 if ($p1 === false)
609 {
610 $sqlBatch = "";
611 }
612 elseif ($p < $p1)
613 {
614 $sqlBatch = mb_substr($sqlBatch, $p);
615 }
616 else
617 {
618 $sqlBatch = mb_substr($sqlBatch, $p1);
619 }
620 }
621 else
622 {
623 $sqlBatch = mb_substr($sqlBatch, $p);
624 }
625 }
626 //$$ plpgsql body
627 elseif ($match[2] == '$$')
628 {
629 //Take that was before delimiter as part of sql
630 $sqlBatch = mb_substr($sqlBatch, mb_strlen($match[0]));
631 //Including $$
632 $sql .= $match[0];
633 //Find closing $$
634 $p = mb_strpos($sqlBatch, '$$');
635 if ($p === false)
636 {
637 $sql .= $sqlBatch;
638 $sqlBatch = '';
639 }
640 else
641 {
642 $sql .= mb_substr($sqlBatch, 0, $p + 2);
643 $sqlBatch = mb_substr($sqlBatch, $p + 2);
644 }
645 }
646 //Delimiter!
647 else
648 {
649 //Take that was before delimiter as part of sql
650 $sqlBatch = mb_substr($sqlBatch, mb_strlen($match[0]));
651 $sql .= $match[1];
652 //Delimiter must be followed by whitespace
653 if (preg_match("%^[\n\r\t ]%", $sqlBatch))
654 {
655 $sql = trim($sql);
656 if (!empty($sql))
657 {
658 $statements[] = str_replace("\r\n", "\n", $sql);
659 $sql = "";
660 }
661 }
662 //It was not delimiter!
663 elseif (!empty($sqlBatch))
664 {
665 $sql .= $match[2];
666 }
667 }
668 }
669 else //End of file is our delimiter
670 {
671 $sql .= $sqlBatch;
672 $sqlBatch = "";
673 }
674 }
675 while (!empty($sqlBatch));
676
677 $sql = trim($sql, " \t\n\r");
678 if (!empty($sql))
679 {
680 $statements[] = str_replace("\r\n", "\n", $sql);
681 }
682
683 return $statements;
684 }
685
691 abstract public function getAffectedRowsCount();
692
693 /*********************************************************
694 * DDL
695 *********************************************************/
696
704 abstract public function isTableExists($tableName);
705
717 abstract public function isIndexExists($tableName, array $columns);
718
728 abstract public function getIndexName($tableName, array $columns, $strict = false);
729
739 abstract public function getTableFields($tableName);
740
750 abstract public function createTable($tableName, $fields, $primary = [], $autoincrement = []);
751
762 public function createPrimaryIndex($tableName, $columnNames)
763 {
764 if (!is_array($columnNames))
765 {
766 $columnNames = [$columnNames];
767 }
768
769 foreach ($columnNames as &$columnName)
770 {
771 $columnName = $this->getSqlHelper()->quote($columnName);
772 }
773
774 $sql = 'ALTER TABLE ' . $this->getSqlHelper()->quote($tableName) . ' ADD PRIMARY KEY(' . join(', ', $columnNames) . ')';
775
776 return $this->query($sql);
777 }
778
790 public function createIndex($tableName, $indexName, $columnNames)
791 {
792 if (!is_array($columnNames))
793 {
794 $columnNames = [$columnNames];
795 }
796
797 $sqlHelper = $this->getSqlHelper();
798
799 foreach ($columnNames as &$columnName)
800 {
801 $columnName = $sqlHelper->quote($columnName);
802 }
803 unset($columnName);
804
805 $sql = 'CREATE INDEX ' . $sqlHelper->quote($indexName) . ' ON ' . $sqlHelper->quote($tableName) . ' (' . join(', ', $columnNames) . ')';
806
807 return $this->query($sql);
808 }
809
819 public function getTableField($tableName, $columnName)
820 {
821 $tableFields = $this->getTableFields($tableName);
822
823 return ($tableFields[$columnName] ?? null);
824 }
825
832 public function truncateTable($tableName)
833 {
834 return $this->query('TRUNCATE TABLE ' . $this->getSqlHelper()->quote($tableName));
835 }
836
846 abstract public function renameTable($currentName, $newName);
847
858 public function dropColumn($tableName, $columnName)
859 {
860 $this->query('ALTER TABLE ' . $this->getSqlHelper()->quote($tableName) . ' DROP COLUMN ' . $this->getSqlHelper()->quote($columnName));
861 }
862
871 abstract public function dropTable($tableName);
872
873 /*********************************************************
874 * Transaction
875 *********************************************************/
876
883 abstract public function startTransaction();
884
891 abstract public function commitTransaction();
892
899 abstract public function rollbackTransaction();
900
901 /*********************************************************
902 * Global named lock
903 *********************************************************/
904
911 public function lock($name, $timeout = 0)
912 {
913 return true;
914 }
915
921 public function unlock($name)
922 {
923 return true;
924 }
925
926 /*********************************************************
927 * Tracker
928 *********************************************************/
929
937 public function startTracker($reset = false)
938 {
939 if ($this->sqlTracker == null)
940 {
941 $this->sqlTracker = new Diag\SqlTracker();
942 }
943 if ($reset)
944 {
945 $this->sqlTracker->reset();
946 }
947
948 $this->trackSql = true;
949 return $this->sqlTracker;
950 }
951
957 public function stopTracker()
958 {
959 $this->trackSql = false;
960 }
961
968 public function getTracker()
969 {
970 return $this->sqlTracker;
971 }
972
980 public function setTracker(Diag\SqlTracker $sqlTracker = null)
981 {
982 $this->sqlTracker = $sqlTracker;
983 }
984
985 /*********************************************************
986 * Type, version, cache, etc.
987 *********************************************************/
988
999 abstract public function getType();
1000
1010 abstract public function getVersion();
1011
1017 abstract public function getErrorMessage();
1018
1024 public function getErrorCode()
1025 {
1026 return 0;
1027 }
1028
1034 public function clearCaches()
1035 {
1036 $this->tableColumnsCache = [];
1037 }
1038
1045 public function setNodeId($nodeId)
1046 {
1047 $this->nodeId = $nodeId;
1048 }
1049
1055 public function getNodeId()
1056 {
1057 return $this->nodeId;
1058 }
1059
1060 protected function afterConnected()
1061 {
1062 if (isset($this->configuration["include_after_connected"]) && $this->configuration["include_after_connected"] <> '')
1063 {
1064 include($this->configuration["include_after_connected"]);
1065 }
1066 }
1067
1075 public function isUtf8mb4($table = null, $column = null)
1076 {
1077 if (isset($this->utf8mb4["global"]) && $this->utf8mb4["global"] === true)
1078 {
1079 return true;
1080 }
1081
1082 if ($table !== null && isset($this->utf8mb4["tables"][$table]) && $this->utf8mb4["tables"][$table] === true)
1083 {
1084 return true;
1085 }
1086
1087 if ($table !== null && $column !== null && isset($this->utf8mb4["tables"][$table][$column]) && $this->utf8mb4["tables"][$table][$column] === true)
1088 {
1089 return true;
1090 }
1091
1092 return false;
1093 }
1094
1095 protected static function findIndex(array $indexes, array $columns, $strict)
1096 {
1097 $columnsList = implode(",", $columns);
1098
1099 foreach ($indexes as $indexName => $indexColumns)
1100 {
1101 ksort($indexColumns);
1102 $indexColumnList = implode(",", $indexColumns);
1103 if ($strict)
1104 {
1105 if ($indexColumnList === $columnsList)
1106 {
1107 return $indexName;
1108 }
1109 }
1110 else
1111 {
1112 if (str_starts_with($indexColumnList, $columnsList))
1113 {
1114 return $indexName;
1115 }
1116 }
1117 }
1118
1119 return null;
1120 }
1121
1129 public function createQueryException($code = 0, $databaseMessage = '', $query = '')
1130 {
1131 return new SqlQueryException('Query error', $databaseMessage, $query);
1132 }
1133}
$connection
Определения actionsdefinitions.php:38
$login
Определения change_password.php:8
static getInstance()
Определения application.php:98
setTracker(Diag\SqlTracker $sqlTracker=null)
Определения connection.php:980
disableQueryExecuting()
Определения connection.php:134
static findIndex(array $indexes, array $columns, $strict)
Определения connection.php:1095
getTableField($tableName, $columnName)
Определения connection.php:819
static parseQueryFunctionArgs($args)
Определения connection.php:384
isUtf8mb4($table=null, $column=null)
Определения connection.php:1075
getIndexName($tableName, array $columns, $strict=false)
setNodeId($nodeId)
Определения connection.php:1045
unlock($name)
Определения connection.php:921
createResult($result, Diag\SqlTrackerQuery $trackerQuery=null)
const PERSISTENT
Определения connection.php:19
createIndex($tableName, $indexName, $columnNames)
Определения connection.php:790
createPrimaryIndex($tableName, $columnNames)
Определения connection.php:762
executeSqlBatch($sqlBatch, $stopOnError=false)
Определения connection.php:538
startTracker($reset=false)
Определения connection.php:937
query($sql)
Определения connection.php:299
queryInternal($sql, array $binds=null, Diag\SqlTrackerQuery $trackerQuery=null)
parseSqlBatch($sqlBatch)
Определения connection.php:566
renameTable($currentName, $newName)
lock($name, $timeout=0)
Определения connection.php:911
dropColumn($tableName, $columnName)
Определения connection.php:858
isIndexExists($tableName, array $columns)
createQueryException($code=0, $databaseMessage='', $query='')
Определения connection.php:1129
const INDEX_SPATIAL
Определения connection.php:23
$disabledQueryExecutingDump
Определения connection.php:48
const INDEX_FULLTEXT
Определения connection.php:22
$queryExecutingEnabled
Определения connection.php:46
isQueryExecutingEnabled()
Определения connection.php:158
addMulti($tableName, $rows, $identity="ID")
Определения connection.php:471
const INDEX_UNIQUE
Определения connection.php:21
enableQueryExecuting()
Определения connection.php:147
getDisabledQueryExecutingDump()
Определения connection.php:171
add($tableName, array $data, $identity="ID")
Определения connection.php:450
queryScalar($sql, array $binds=null)
Определения connection.php:350
const DEFERRED
Определения connection.php:20
queryExecute($sql, array $binds=null)
Определения connection.php:371
$tableColumnsCache
Определения connection.php:40
createTable($tableName, $fields, $primary=[], $autoincrement=[])
truncateTable($tableName)
Определения connection.php:832
__construct(array $configuration)
Определения connection.php:63
$data['IS_AVAILABLE']
Определения .description.php:13
$sqlTracker
Определения debug_info.php:28
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$result
Определения get_property_values.php:14
$query
Определения get_search.php:11
$p
Определения group_list_element_edit.php:23
if(!is_null($config))($config as $configItem)(! $configItem->isVisible()) $code
Определения options.php:195
$name
Определения menu_edit.php:35
Определения cachetracker.php:2
$password
Определения mysql_to_pgsql.php:34
$host
Определения mysql_to_pgsql.php:32
$table
Определения mysql_to_pgsql.php:36
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
$rows
Определения options.php:264
$fields
Определения yandex_run.php:501