vendor\kafoso\doctrine-firebird-driver\src\Driver\FirebirdInterbase\Connection.php line 103

Open in your IDE?
  1. <?php
  2. namespace IST\DoctrineFirebirdDriver\Driver\FirebirdInterbase;
  3. use Doctrine\DBAL\Driver\Connection as ConnectionInterface;
  4. use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
  5. use IST\DoctrineFirebirdDriver\Driver\ConfigurationInterface;
  6. /**
  7.  * Based on https://github.com/helicon-os/doctrine-dbal
  8.  */
  9. class Connection implements ConnectionInterfaceServerInfoAwareConnection
  10. {
  11.     const TRANSACTIONS_MAXIMUM_LEVEL 20;
  12.     /**
  13.      * @var Configuration
  14.      */
  15.     private $_configuration;
  16.     /**
  17.      * @var resource (ibase_pconnect or ibase_connect)
  18.      */
  19.     private $_ibaseConnectionRc;
  20.     /**
  21.      * @var int
  22.      */
  23.     private $_ibaseTransactionLevel 0;
  24.     /**
  25.      * @var resource
  26.      */
  27.     private $_ibaseActiveTransaction null;
  28.     /**
  29.      * Isolation level used when a transaction is started.
  30.      * @var int
  31.      */
  32.     protected $attrDcTransIsolationLevel = \Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED;
  33.     /**
  34.      * Wait timeout used in transactions
  35.      *
  36.      * @var integer  Number of seconds to wait.
  37.      */
  38.     protected $attrDcTransWait 5;
  39.     /**
  40.      * True if auto-commit is enabled
  41.      * @var boolean
  42.      */
  43.     protected $attrAutoCommit true;
  44.     /**
  45.      * @throws Exception
  46.      */
  47.     public function __construct(Configuration $configuration)
  48.     {
  49.         $this->_configuration $configuration;
  50.         foreach ($this->_configuration->getDriverOptions() as $k => $v) {
  51.             $this->setAttribute($k$v);
  52.         }
  53.         $this->connect();
  54.     }
  55.     public function __destruct()
  56.     {
  57.         $this->autoCommit();
  58.         $success = @ibase_close($this->_ibaseConnectionRc);
  59.         if (false == $success) {
  60.             $this->checkLastApiCall();
  61.         }
  62.     }
  63.     public function connect()
  64.     {
  65.         if (!$this->_ibaseConnectionRc || !is_resource($this->_ibaseConnectionRc)) {
  66.             if ($this->_configuration->isPersistent()) {
  67.                 $this->_ibaseConnectionRc = @ibase_pconnect(
  68.                     $this->_configuration->getFullHostString(),
  69.                     $this->_configuration->getUsername(),
  70.                     $this->_configuration->getPassword(),
  71.                     $this->_configuration->getCharset(),
  72.                     $this->_configuration->getBuffers(),
  73.                     $this->_configuration->getDialect()
  74.                 );
  75.             } else {
  76.                 $this->_ibaseConnectionRc = @ibase_connect(
  77.                     $this->_configuration->getFullHostString(),
  78.                     $this->_configuration->getUsername(),
  79.                     $this->_configuration->getPassword(),
  80.                     $this->_configuration->getCharset(),
  81.                     $this->_configuration->getBuffers(),
  82.                     $this->_configuration->getDialect()
  83.                 );
  84.             }
  85.             if (!is_resource($this->_ibaseConnectionRc)) {
  86.                 $this->checkLastApiCall();
  87.             }
  88.             if (!is_resource($this->_ibaseConnectionRc)) {
  89.                 throw Exception::fromErrorInfo($this->errorInfo());
  90.             }
  91.             $this->_ibaseActiveTransaction $this->createTransaction(true);
  92.         }
  93.     }
  94.     /**
  95.      * {@inheritDoc}
  96.      *
  97.      * Additionally to the standard driver attributes, the attribute
  98.      * {@link Configuration::ATTR_DOCTRINE_DEFAULT_TRANS_ISOLATION_LEVEL} can be used to control
  99.      * the isolation level used for transactions
  100.      *
  101.      * @param string $attribute
  102.      * @param mixed $value
  103.      */
  104.     public function setAttribute($attribute$value)
  105.     {
  106.         switch ($attribute) {
  107.             case Configuration::ATTR_DOCTRINE_DEFAULT_TRANS_ISOLATION_LEVEL:
  108.                 $this->attrDcTransIsolationLevel $value;
  109.                 break;
  110.             case Configuration::ATTR_DOCTRINE_DEFAULT_TRANS_WAIT:
  111.                 $this->attrDcTransWait $value;
  112.                 break;
  113.             case \PDO::ATTR_AUTOCOMMIT:
  114.                 $this->attrAutoCommit $value;
  115.                 break;
  116.         }
  117.     }
  118.     /**
  119.      * {@inheritDoc}
  120.      *
  121.      * @param string $attribute
  122.      * @return mixed
  123.      */
  124.     public function getAttribute($attribute)
  125.     {
  126.         switch ($attribute) {
  127.             case Configuration::ATTR_DOCTRINE_DEFAULT_TRANS_ISOLATION_LEVEL:
  128.                 return $this->attrDcTransIsolationLevel;
  129.             case Configuration::ATTR_DOCTRINE_DEFAULT_TRANS_WAIT:
  130.                 return $this->attrDcTransWait;
  131.             case \PDO::ATTR_AUTOCOMMIT:
  132.                 return $this->attrAutoCommit;
  133.         }
  134.     }
  135.     /**
  136.      * @return ConfigurationInterface
  137.      */
  138.     public function getConfiguration()
  139.     {
  140.         return $this->_configuration;
  141.     }
  142.     /**
  143.      * @return resource (ibase_pconnect or ibase_connect)
  144.      */
  145.     public function getInterbaseConnectionResource()
  146.     {
  147.         return $this->_ibaseConnectionRc;
  148.     }
  149.     /**
  150.      * {@inheritdoc}
  151.      */
  152.     public function getServerVersion()
  153.     {
  154.         return ibase_server_info($this->_ibaseConnectionRcIBASE_SVC_SERVER_VERSION);
  155.     }
  156.     /**
  157.      * {@inheritdoc}
  158.      */
  159.     public function requiresQueryForServerVersion()
  160.     {
  161.         return false;
  162.     }
  163.     /**
  164.      * {@inheritdoc}
  165.      */
  166.     public function prepare($prepareString)
  167.     {
  168.         return new Statement($this$prepareString);
  169.     }
  170.     /**
  171.      * {@inheritdoc}
  172.      */
  173.     public function query()
  174.     {
  175.         $args func_get_args();
  176.         $sql $args[0];
  177.         $stmt $this->prepare($sql);
  178.         $stmt->execute();
  179.         return $stmt;
  180.     }
  181.     /**
  182.      * {@inheritdoc}
  183.      */
  184.     public function quote($input$type=\PDO::PARAM_STR)
  185.     {
  186.         if (is_int($value) || is_float($value)) {
  187.             return $value;
  188.         }
  189.         $value str_replace("'""''"$value);
  190.         return "'" addcslashes($value"\000\n\r\\\032") . "'";
  191.     }
  192.     /**
  193.      * {@inheritdoc}
  194.      */
  195.     public function exec($statement)
  196.     {
  197.         $stmt $this->prepare($statement);
  198.         $stmt->execute();
  199.         return $stmt->rowCount();
  200.     }
  201.     /**
  202.      * {@inheritdoc}
  203.      */
  204.     public function lastInsertId($name null)
  205.     {
  206.         if ($name === null) {
  207.             return false;
  208.         }
  209.         $sql "SELECT GEN_ID('{$name}', 0) LAST_VAL FROM RDB\$DATABASE";
  210.         $stmt $this->query($sql);
  211.         $result $stmt->fetchColumn(0);
  212.         return $result;
  213.     }
  214.     /**
  215.      * @param int $isolationLevel
  216.      * @param int $timeout
  217.      * @return string
  218.      */
  219.     public function getStartTransactionSql($isolationLevel$timeout 5)
  220.     {
  221.         $result "";
  222.         switch ($isolationLevel) {
  223.             case \Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED: {
  224.                     $result .= 'SET TRANSACTION READ WRITE ISOLATION LEVEL READ COMMITTED RECORD_VERSION';
  225.                     break;
  226.                 }
  227.             case \Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED: {
  228.                     $result .= 'SET TRANSACTION READ WRITE ISOLATION LEVEL READ COMMITTED RECORD_VERSION';
  229.                     break;
  230.                 }
  231.             case \Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ: {
  232.                     $result .= 'SET TRANSACTION READ WRITE ISOLATION LEVEL SNAPSHOT ';
  233.                     break;
  234.                 }
  235.             case \Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE: {
  236.                     $result .= 'SET TRANSACTION READ WRITE ISOLATION LEVEL SNAPSHOT TABLE STABILITY';
  237.                     break;
  238.                 }
  239.         }
  240.         if (($this->attrDcTransWait 0)) {
  241.             $result .= ' WAIT LOCK TIMEOUT ' $this->attrDcTransWait;
  242.         } elseif  (($this->attrDcTransWait === -1)) {
  243.             $result .= ' WAIT';
  244.         } else {
  245.             $result .= ' NO WAIT';
  246.         }
  247.         return $result;
  248.     }
  249.     /**
  250.      * {@inheritdoc}
  251.      */
  252.     public function beginTransaction()
  253.     {
  254.         if ($this->_ibaseTransactionLevel 1) {
  255.             $this->_ibaseActiveTransaction $this->createTransaction(true);
  256.             $this->_ibaseTransactionLevel++;
  257.         }
  258.         return true;
  259.     }
  260.     /**
  261.      * {@inheritdoc}
  262.      */
  263.     public function commit()
  264.     {
  265.         if ($this->_ibaseTransactionLevel 0) {
  266.             if (!$this->_ibaseActiveTransaction || false == is_resource($this->_ibaseActiveTransaction)) {
  267.                 throw new \RuntimeException(sprintf(
  268.                     "No active transaction. \$this->_ibaseTransactionLevel = %d",
  269.                     $this->_ibaseTransactionLevel
  270.                 ));
  271.             }
  272.             $success = @ibase_commit($this->_ibaseActiveTransaction);
  273.             if (false == $success) {
  274.                 $this->checkLastApiCall();
  275.             }
  276.             $this->_ibaseTransactionLevel--;
  277.         }
  278.         if (== $this->_ibaseTransactionLevel) {
  279.             $this->_ibaseActiveTransaction $this->createTransaction(true);
  280.         }
  281.         return true;
  282.     }
  283.     /**
  284.      * Commits the transaction if autocommit is enabled no explicte transaction has been started.
  285.      * @throws \RuntimeException
  286.      * @return null|bool
  287.      */
  288.     public function autoCommit()
  289.     {
  290.         if ($this->attrAutoCommit && $this->_ibaseTransactionLevel 1) {
  291.             if (!$this->_ibaseActiveTransaction || false == is_resource($this->_ibaseActiveTransaction)) {
  292.                 throw new \RuntimeException(sprintf(
  293.                     "No active transaction. \$this->_ibaseTransactionLevel = %d",
  294.                     $this->_ibaseTransactionLevel
  295.                 ));
  296.             }
  297.             $success = @ibase_commit_ret($this->getActiveTransaction());
  298.             if (false == $success) {
  299.                 $this->checkLastApiCall();
  300.             }
  301.             return true;
  302.         }
  303.         return null;
  304.     }
  305.     /**
  306.      * {@inheritdoc)
  307.      * @throws \RuntimeException
  308.      */
  309.     public function rollBack()
  310.     {
  311.         if ($this->_ibaseTransactionLevel 0) {
  312.             if (!$this->_ibaseActiveTransaction || false == is_resource($this->_ibaseActiveTransaction)) {
  313.                 throw new \RuntimeException(sprintf(
  314.                     "No active transaction. \$this->_ibaseTransactionLevel = %d",
  315.                     $this->_ibaseTransactionLevel
  316.                 ));
  317.             }
  318.             $success = @ibase_rollback($this->_ibaseActiveTransaction);
  319.             if (false == $success) {
  320.                 $this->checkLastApiCall();
  321.             }
  322.             $this->_ibaseTransactionLevel--;
  323.         }
  324.         $this->_ibaseActiveTransaction $this->createTransaction(true);
  325.         return true;
  326.     }
  327.     /**
  328.      * {@inheritdoc}
  329.      */
  330.     public function errorCode()
  331.     {
  332.         return ibase_errcode();
  333.     }
  334.     /**
  335.      * {@inheritdoc}
  336.      */
  337.     public function errorInfo()
  338.     {
  339.         $errorCode $this->errorCode();
  340.         if ($errorCode) {
  341.             return [
  342.                 'code' => $errorCode,
  343.                 'message' => ibase_errmsg(),
  344.             ];
  345.         }
  346.         return [
  347.             'code' => 0,
  348.             'message' => null,
  349.         ];
  350.     }
  351.     /**
  352.      * @throws \RuntimeException
  353.      * @return resource
  354.      */
  355.     public function getActiveTransaction()
  356.     {
  357.         $this->connect();
  358.         if (!$this->_ibaseActiveTransaction || false == is_resource($this->_ibaseActiveTransaction)) {
  359.             throw new \RuntimeException(sprintf(
  360.                 "No active transaction. \$this->_ibaseTransactionLevel = %d",
  361.                 $this->_ibaseTransactionLevel
  362.             ));
  363.         }
  364.         return $this->_ibaseActiveTransaction;
  365.     }
  366.     /**
  367.      * Checks ibase_error and raises an exception if an error occured
  368.      *
  369.      * @throws Exception
  370.      */
  371.     protected function checkLastApiCall()
  372.     {
  373.         $lastError $this->errorInfo();
  374.         if (isset($lastError['code']) && $lastError['code']) {
  375.             throw Exception::fromErrorInfo($lastError);
  376.         }
  377.     }
  378.     /**
  379.      * @param bool $commitDefaultTransaction
  380.      * @return resource The ibase transaction.
  381.      */
  382.     protected function createTransaction($commitDefaultTransaction true)
  383.     {
  384.         if ($commitDefaultTransaction) {
  385.             @ibase_commit($this->_ibaseConnectionRc);
  386.         }
  387.         $sql $this->getStartTransactionSql($this->attrDcTransIsolationLevel);
  388.         $result = @ibase_query($this->_ibaseConnectionRc$sql);
  389.         if (false == is_resource($result)) {
  390.             $this->checkLastApiCall();
  391.         }
  392.         return $result;
  393.     }
  394. }