Your IP : 3.15.147.162


Current Path : /home/bitrix/ext_www/rk_shared_core/bitrix/modules/sale/lib/location/db/
Upload File :
Current File : /home/bitrix/ext_www/rk_shared_core/bitrix/modules/sale/lib/location/db/blockinserter.php

<?
/**
 * This class is for internal use only, not a part of public API.
 * It can be changed at any time without notification.
 *
 * @access private
 */

namespace Bitrix\Sale\Location\DB;

use Bitrix\Main;

use Bitrix\Sale\Location\DB\Helper;

class BlockInserter
{
	protected $tableName = 		'';
	protected $tableMap = 		array();
	protected $fldVector = 		array();

	protected $insertHead = 	'';
	protected $insertTail = 	'';
	protected $index = 			0;
	protected $bufferSize = 	0;
	protected $buffer = 		'';
	protected $map = 			array();

	protected $autoIncFld = 	false;
	protected $dbType = 		false;
	protected $mtu = 			0;

	protected $dbConnection = 	null;
	protected $dbHelper = 		null;

	protected $callbacks = 		array();

	const RED_LINE = 			100;

	public function __construct($parameters = array())
	{
		$this->dbConnection = Main\HttpApplication::getConnection();
		$this->dbHelper = $this->dbConnection->getSqlHelper();

		$map = array();
		if(strlen($parameters['entityName']))
		{
			$table = $parameters['entityName'];

			$this->tableName = $table::getTableName();
			$this->tableMap = $table::getMap();

			// filter map throught $parameters['exactFields']
			if(is_array($parameters['exactFields']) && !empty($parameters['exactFields']))
			{
				foreach($parameters['exactFields'] as $fld)
				{
					if(!isset($this->tableMap[$fld]))
						throw new Main\SystemException('Field does not exist in ORM class, but present in "exactFields" parameter: '.$fld, 0, __FILE__, __LINE__);

					$map[] = $fld;
					$this->fldVector[$fld] = true;
				}
			}
			else
			{
				foreach($this->tableMap as $fld => $params)
				{
					$map[] = $fld;
					$this->fldVector[$fld] = true;
				}
			}
		}
		elseif(strlen($parameters['tableName']))
		{
			$this->tableName = $this->dbHelper->forSql($parameters['tableName']);
			$this->tableMap = $parameters['exactFields'];

			// $this->tableMap as $fld => $params - is the right way!
			/*
			required for

				$loc2site = new DB\BlockInserter(array(
					'tableName' => 'b_sale_loc_2site',
					'exactFields' => array(
						'LOCATION_ID' => array('data_type' => 'integer'),
						'SITE_ID' => array('data_type' => 'string')
					),
					'parameters' => array(
						'mtu' => 9999,
						'autoIncrementFld' => 'ID'
					)
				));
			*/
			foreach($this->tableMap as $fld => $params)
			{
				$map[] = $fld;
				$this->fldVector[$fld] = true;
			}
		}

		// automatically insert to this field an auto-increment value
		// beware of TransactSQL`s IDENTITY_INSERT when setting autoIncrementFld to a database-driven auto-increment field
		if(strlen($parameters['parameters']['autoIncrementFld']))
		{
			$this->autoIncFld = $this->dbHelper->forSql($this->autoIncFld);

			$this->autoIncFld = $parameters['parameters']['autoIncrementFld'];
			if(!isset($this->fldVector[$this->autoIncFld]))
			{
				$map[] = $this->autoIncFld;
				$this->fldVector[$this->autoIncFld] = true;
				$this->tableMap[$this->autoIncFld] = array('data_type' => 'integer');
			}

			$this->initIndexFromField();
		}

		$this->dbType = Main\HttpApplication::getConnection()->getType();

		if(!($this->mtu = intval($parameters['parameters']['mtu'])))
			$this->mtu = 9999;

		$dbMtu = Helper::getMaxTransferUnit();
		if($this->mtu > $dbMtu)
			$this->mtu = $dbMtu;

		$this->insertHead = Helper::getBatchInsertHead($this->tableName, $map);
		$this->insertTail = Helper::getBatchInsertTail();

		if(is_callable($parameters['parameters']['CALLBACKS']['ON_BEFORE_FLUSH']))
			$this->callbacks['ON_BEFORE_FLUSH'] = $parameters['parameters']['CALLBACKS']['ON_BEFORE_FLUSH'];

		$this->map = $map;
	}

	// this method is buggy when table is empty
	public function initIndexFromField($fld = 'ID')
	{
		if(!strlen($fld))
			throw new Main\SystemException('Field is not set');

		$fld = $this->dbHelper->forSql($fld);

		$sql = 'select MAX('.$fld.') as VAL from '.$this->tableName;

		$res = $this->dbConnection->query($sql)->fetch();
		$this->index = intval($res['VAL']);

		/*
		$sql = 'select '.$fld.' from '.$this->tableName.' order by '.$fld.' desc';
		$sql = $this->dbHelper->getTopSql($sql, 1);

		$res = $this->dbConnection->query($sql)->fetch();
		$this->index = intval($res[$this->autoIncFld]);
		*/

		return $this->index;
	}

	public function getIndex()
	{
		return $this->index;
	}

	public function dropAutoIncrementRestrictions()
	{
		if($this->autoIncFld === false)
			return false;

		return Helper::dropAutoIncrementRestrictions($this->tableName);
	}

	public function restoreAutoIncrementRestrictions()
	{
		if($this->autoIncFld === false)
			return false;

		return Helper::restoreAutoIncrementRestrictions($this->tableName);
	}

	public function resetAutoIncrementFromIndex()
	{
		Helper::resetAutoIncrement($this->tableName, $this->getIndex() + 1);
	}

	public function insert($row)
	{
		if(!is_array($row) || empty($row))
			return;

		$this->index++;
		$this->bufferSize++;

		if($this->autoIncFld !== false)
		{
			$row[$this->autoIncFld] = $this->index;
			Helper::incrementSequenceForTable($this->tableName); // if this is oracle and we insert auto increment key directly, we must provide sequence increment manually
		}

		$sql = Helper::getBatchInsertValues($row, $this->tableName, $this->fldVector, $this->map);

		/*
		MySQL & MsSQL: insert into b_test (F1,F2) values ('one','two'),('one1','two1'),('one2','two2')
		Oracle: insert all into b_test (F1,F2) values ('one','two') into b_test (F1,F2) values ('one1','two1') into b_test (F1,F2) values ('one2','two2')  select * from dual
		*/

		$nextBuffer = (empty($this->buffer) ? $this->insertHead : $this->buffer.Helper::getBatchInsertSeparator()).$sql;

		// here check length
		if(defined(SITE_CHARSET) && SITE_CHARSET == 'UTF-8')
			$len = mb_strlen($nextBuffer);
		else
			$len = strlen($nextBuffer);

		if(($this->mtu - (strlen($nextBuffer) + 100)) < self::RED_LINE)
		{
			$this->flush(); // flushing the previous buffer (now $this->buffer == '')
			$this->buffer = $this->insertHead.$sql;
		}
		else
			$this->buffer = $nextBuffer;

		return $this->index;
	}

	public function flush()
	{
		if(!strlen($this->buffer))
			return;

		if(isset($this->callbacks['ON_BEFORE_FLUSH']))
			call_user_func($this->callbacks['ON_BEFORE_FLUSH']);

		$this->buffer .= ' '.$this->insertTail;

		$restrDropped = $this->dropAutoIncrementRestrictions();

		Main\HttpApplication::getConnection()->query($this->buffer);

		if($restrDropped)
			$this->restoreAutoIncrementRestrictions();

		$this->buffer = '';
		$this->bufferSize = 0;
	}
}