Your IP : 3.133.97.254


Current Path : /var/www/www-root/data/webdav/www/monolith-realty.ru/bitrix/modules/main/lib/db/
Upload File :
Current File : /var/www/www-root/data/webdav/www/monolith-realty.ru/bitrix/modules/main/lib/db/oraclesqlhelper.php

<?php

namespace Bitrix\Main\DB;

use Bitrix\Main\Type;
use Bitrix\Main\ORM;
use Bitrix\Main\ORM\Fields\ScalarField;

class OracleSqlHelper extends SqlHelper
{
	/**
	 * @inheritdoc
	 */
	public function getLeftQuote()
	{
		return '"';
	}

	/**
	 * @inheritdoc
	 */
	public function getRightQuote()
	{
		return '"';
	}

	/**
	 * @inheritdoc
	 */
	public function getAliasLength()
	{
		return 30;
	}

	/**
	 * @inheritdoc
	 */
	public function quote($identifier)
	{
		return parent::quote(mb_strtoupper($identifier));
	}

	/**
	 * @inheritdoc
	 */
	public function getQueryDelimiter()
	{
		return "(?<!\\*)/(?!\\*)";
	}

	/**
	 * @inheritdoc
	 */
	function forSql($value, $maxLength = 0)
	{
		if ($maxLength <= 0 || $maxLength > 2000)
			$maxLength = 2000;

		$value = mb_substr($value, 0, $maxLength);

		if (\Bitrix\Main\Application::isUtfMode())
		{
			// From http://w3.org/International/questions/qa-forms-utf-8.html
			// This one can crash php with segmentation fault on large input data (over 20K)
			// https://bugs.php.net/bug.php?id=60423
			if (preg_match_all('%(
				[\x00-\x7E]                        # ASCII
				|[\xC2-\xDF][\x80-\xBF]            # non-overlong 2-byte
				|\xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
				|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
				|\xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
				|\xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
				|[\xF1-\xF3][\x80-\xBF]{3}         # planes 4-15
				|\xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
			)+%x', $value, $match))
				$value = implode(' ', $match[0]);
			else
				return ''; //There is no valid utf at all
		}

		return str_replace("'", "''", $value);
	}

	/**
	 * @inheritdoc
	 */
	public function getCurrentDateTimeFunction()
	{
		return "SYSDATE";
	}

	/**
	 * @inheritdoc
	 */
	public function getCurrentDateFunction()
	{
		return "TRUNC(SYSDATE)";
	}

	/**
	 * @inheritdoc
	 */
	public function addSecondsToDateTime($seconds, $from = null)
	{
		if ($from === null)
		{
			$from = static::getCurrentDateTimeFunction();
		}

		return '('.$from.'+'.$seconds.'/86400)';
	}

	/**
	 * @inheritdoc
	 */
	public function getDatetimeToDateFunction($value)
	{
		return 'TRUNC('.$value.')';
	}

	/**
	 * @inheritdoc
	 */
	public function formatDate($format, $field = null)
	{
		$format = str_replace("HH", "HH24", $format);
		$format = str_replace("GG", "HH24", $format);

		if (!str_contains($format, 'HH24'))
		{
			$format = str_replace("H", "HH", $format);
		}

		$format = str_replace("G", "HH", $format);

		$format = str_replace("MI", "II", $format);

		if (str_contains($format, 'MMMM'))
		{
			$format = str_replace("MMMM", "MONTH", $format);
		}
		elseif (!str_contains($format, 'MM'))
		{
			$format = str_replace("M", "MON", $format);
		}

		$format = str_replace("II", "MI", $format);

		$format = str_replace("TT", "AM", $format);
		$format = str_replace("T", "AM", $format);

		if ($field === null)
		{
			return $format;
		}
		else
		{
			return "TO_CHAR(".$field.", '".$format."')";
		}
	}

	/**
	 * @inheritdoc
	 */
	public function getConcatFunction()
	{
		return implode(" || ", func_get_args());
	}

	/**
	 * @inheritdoc
	 */
	public function getIsNullFunction($expression, $result)
	{
		return "NVL(".$expression.", ".$result.")";
	}

	/**
	 * @inheritdoc
	 */
	public function getLengthFunction($field)
	{
		return "LENGTH(".$field.")";
	}

	/**
	 * @inheritdoc
	 */
	public function getCharToDateFunction($value)
	{
		return "TO_DATE('".$value."', 'YYYY-MM-DD HH24:MI:SS')";
	}

	/**
	 * @inheritdoc
	 */
	public function getDateToCharFunction($fieldName)
	{
		return "TO_CHAR(".$fieldName.", 'YYYY-MM-DD HH24:MI:SS')";
	}

	/**
	 * @inheritdoc
	 */
	protected function prepareBinds(array $tableFields, array $fields)
	{
		$binds = array();

		foreach ($tableFields as $columnName => $tableField)
		{
			if (isset($fields[$columnName]) && !($fields[$columnName] instanceof SqlExpression))
			{
				if ($tableField instanceof ORM\Fields\TextField && $fields[$columnName] <> '')
				{
					$binds[$columnName] = $fields[$columnName];
				}
			}
		}

		return $binds;
	}

	/**
	 * @inheritdoc
	 */
	public function getConverter(ScalarField $field)
	{
		if ($field instanceof ORM\Fields\DatetimeField)
		{
			return array($this, "convertFromDbDateTime");
		}
		elseif ($field instanceof ORM\Fields\TextField)
		{
			return array($this, "convertFromDbText");
		}
		elseif ($field instanceof ORM\Fields\StringField)
		{
			return array($this, "convertFromDbString");
		}
		else
		{
			return parent::getConverter($field);
		}
	}

	/**
	 * @inheritdoc
	 */
	public function convertFromDbDateTime($value)
	{
		if ($value !== null)
		{
			if (mb_strlen($value) == 19)
			{
				//preferable format: NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'
				$value = new Type\DateTime($value, "Y-m-d H:i:s");
			}
			else
			{
				//default Oracle date format: 03-MAR-14
				$value = new Type\DateTime($value." 00:00:00", "d-M-y H:i:s");
			}
		}

		return $value;
	}

	/**
	 * @inheritdoc
	 */
	public function convertFromDbText($value)
	{
		if (is_object($value))
		{
			/** @var \OCI_Lob $value */
			$value = $value->load();
		}

		return $value;
	}

	/**
	 * @inheritdoc
	 */
	public function convertToDbText($value)
	{
		return empty($value) ? "NULL" : "EMPTY_CLOB()";
	}

	/**
	 * @inheritdoc
	 */
	public function convertFromDbString($value, $length = null)
	{
		if ($value !== null)
		{
			if ((mb_strlen($value) == 19) && preg_match("#^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$#", $value))
			{
				return new Type\DateTime($value, "Y-m-d H:i:s");
			}
		}

		return parent::convertFromDbString($value, $length);
	}

	/**
	 * @inheritdoc
	 */
	public function castToChar($fieldName)
	{
		return 'TO_CHAR('.$fieldName.')';
	}

	/**
	 * @inheritdoc
	 */
	public function softCastTextToChar($fieldName)
	{
		return 'dbms_lob.substr('.$fieldName.', 4000, 1)';
	}

	/**
	 * @inheritdoc
	 */
	public function getColumnTypeByField(ScalarField $field)
	{
		if ($field instanceof ORM\Fields\IntegerField)
		{
			return 'number(18)';
		}
		elseif ($field instanceof ORM\Fields\FloatField)
		{
			$scale = $field->getScale();
			return 'number'.($scale !== null? "(*,".$scale.")": "");
		}
		elseif ($field instanceof ORM\Fields\DatetimeField)
		{
			return 'date';
		}
		elseif ($field instanceof ORM\Fields\DateField)
		{
			return 'date';
		}
		elseif ($field instanceof ORM\Fields\TextField)
		{
			return 'clob';
		}
		elseif ($field instanceof ORM\Fields\BooleanField)
		{
			$values = $field->getValues();

			if (preg_match('/^[0-9]+$/', $values[0]) && preg_match('/^[0-9]+$/', $values[1]))
			{
				return 'number(1)';
			}
			else
			{
				return 'varchar2('.max(mb_strlen($values[0]), mb_strlen($values[1])).' char)';
			}
		}
		elseif ($field instanceof ORM\Fields\EnumField)
		{
			return 'varchar2('.max(array_map('strlen', $field->getValues())).' char)';
		}
		else
		{
			// string by default
			$defaultLength = false;
			foreach ($field->getValidators() as $validator)
			{
				if ($validator instanceof ORM\Fields\Validators\LengthValidator)
				{
					if ($defaultLength === false || $defaultLength > $validator->getMax())
					{
						$defaultLength = $validator->getMax();
					}
				}
			}
			return 'varchar2('.($defaultLength > 0? $defaultLength: 255).' char)';
		}
	}

	/**
	 * @inheritdoc
	 */
	public function getFieldByColumnType($name, $type, array $parameters = null)
	{
		switch ($type)
		{
		case "DATE":
			return new ORM\Fields\DatetimeField($name);

		case "NCLOB":
		case "CLOB":
		case "BLOB":
			return new ORM\Fields\TextField($name);

		case "FLOAT":
		case "BINARY_FLOAT":
		case "BINARY_DOUBLE":
			return new ORM\Fields\FloatField($name);

		case "NUMBER":
			if ($parameters["precision"] == 0 && $parameters["scale"] == -127)
			{
				//NUMBER
				return new ORM\Fields\FloatField($name);
			}
			if (intval($parameters["scale"]) <= 0)
			{
				//NUMBER(18)
				//NUMBER(18,-2)
				return new ORM\Fields\IntegerField($name);
			}
			//NUMBER(*,2)
			return new ORM\Fields\FloatField($name, array("scale" => $parameters["scale"]));
		}
		//LONG
		//VARCHAR2(size [BYTE | CHAR])
		//NVARCHAR2(size)
		//TIMESTAMP [(fractional_seconds_precision)]
		//TIMESTAMP [(fractional_seconds)] WITH TIME ZONE
		//TIMESTAMP [(fractional_seconds)] WITH LOCAL TIME ZONE
		//INTERVAL YEAR [(year_precision)] TO MONTH
		//INTERVAL DAY [(day_precision)] TO SECOND [(fractional_seconds)]
		//RAW(size)
		//LONG RAW
		//ROWID
		//UROWID [(size)]
		//CHAR [(size [BYTE | CHAR])]
		//NCHAR[(size)]
		//BFILE
		return new ORM\Fields\StringField($name, array("size" => $parameters["size"]));
	}

	/**
	 * @inheritdoc
	 */
	public function getTopSql($sql, $limit, $offset = 0)
	{
		$offset = intval($offset);
		$limit = intval($limit);

		if ($offset > 0 && $limit <= 0)
			throw new \Bitrix\Main\ArgumentException("Limit must be set if offset is set");

		if ($limit > 0)
		{
			//The first row selected has a ROWNUM of 1, the second has 2, and so on
			if ($offset <= 0)
			{
				$sql =
					"SELECT * ".
					"FROM (".$sql.") ".
					"WHERE ROWNUM <= ".$limit;
			}
			else
			{
				$sql =
					"SELECT * ".
					"FROM (".
					"   SELECT rownum_query_alias.*, ROWNUM rownum_alias ".
					"   FROM (".$sql.") rownum_query_alias ".
					"   WHERE ROWNUM <= ".($offset + $limit)." ".
					") ".
					"WHERE rownum_alias >= ".($offset + 1);
			}
		}
		return $sql;
	}

	/**
	 * @inheritdoc
	 */
	public function getAscendingOrder()
	{
		return 'ASC NULLS FIRST';
	}

	/**
	 * @inheritdoc
	 */
	public function getDescendingOrder()
	{
		return 'DESC NULLS LAST';
	}

	/**
	 * @inheritdoc
	 */
	public function prepareMerge($tableName, array $primaryFields, array $insertFields, array $updateFields)
	{
		$insert = $this->prepareInsert($tableName, $insertFields);

		$updateColumns = array();
		$sourceSelectColumns = array();
		$targetConnectColumns = array();
		$tableFields = $this->connection->getTableFields($tableName);
		foreach($tableFields as $columnName => $tableField)
		{
			$quotedName = $this->quote($columnName);
			if (in_array($columnName, $primaryFields))
			{
				$sourceSelectColumns[] = $this->convertToDb($insertFields[$columnName], $tableField)." AS ".$quotedName;
				if($insertFields[$columnName] === null)
				{
					//can't just compare NULLs
					$targetConnectColumns[] = "(source.".$quotedName." IS NULL AND target.".$quotedName." IS NULL)";
				}
				else
				{
					$targetConnectColumns[] = "(source.".$quotedName." = target.".$quotedName.")";
				}
			}

			if (isset($updateFields[$columnName]) || array_key_exists($columnName, $updateFields))
			{
				$updateColumns[] = "target.".$quotedName.' = '.$this->convertToDb($updateFields[$columnName], $tableField);
			}
		}

		if (
			$insert && $insert[0] != "" && $insert[1] != ""
			&& $updateColumns
			&& $sourceSelectColumns && $targetConnectColumns
		)
		{
			$sql = "
				MERGE INTO ".$this->quote($tableName)." target USING (
					SELECT ".implode(", ", $sourceSelectColumns)." FROM dual
				)
				source ON
				(
					".implode(" AND ", $targetConnectColumns)."
				)
				WHEN MATCHED THEN
					UPDATE SET ".implode(", ", $updateColumns)."
				WHEN NOT MATCHED THEN
					INSERT (".$insert[0].")
					VALUES (".$insert[1].")
			";
		}
		else
		{
			$sql = "";
		}

		return array(
			$sql
		);
	}
}