summaryrefslogtreecommitdiff
path: root/vendor/doctrine/dbal/src/Driver/IBMDB2/Statement.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/doctrine/dbal/src/Driver/IBMDB2/Statement.php')
-rw-r--r--vendor/doctrine/dbal/src/Driver/IBMDB2/Statement.php156
1 files changed, 156 insertions, 0 deletions
diff --git a/vendor/doctrine/dbal/src/Driver/IBMDB2/Statement.php b/vendor/doctrine/dbal/src/Driver/IBMDB2/Statement.php
new file mode 100644
index 0000000..96852da
--- /dev/null
+++ b/vendor/doctrine/dbal/src/Driver/IBMDB2/Statement.php
@@ -0,0 +1,156 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Doctrine\DBAL\Driver\IBMDB2;
6
7use Doctrine\DBAL\Driver\Exception;
8use Doctrine\DBAL\Driver\IBMDB2\Exception\CannotCopyStreamToStream;
9use Doctrine\DBAL\Driver\IBMDB2\Exception\CannotCreateTemporaryFile;
10use Doctrine\DBAL\Driver\IBMDB2\Exception\StatementError;
11use Doctrine\DBAL\Driver\Statement as StatementInterface;
12use Doctrine\DBAL\ParameterType;
13
14use function assert;
15use function db2_bind_param;
16use function db2_execute;
17use function error_get_last;
18use function fclose;
19use function is_int;
20use function is_resource;
21use function stream_copy_to_stream;
22use function stream_get_meta_data;
23use function tmpfile;
24
25use const DB2_BINARY;
26use const DB2_CHAR;
27use const DB2_LONG;
28use const DB2_PARAM_FILE;
29use const DB2_PARAM_IN;
30
31final class Statement implements StatementInterface
32{
33 /** @var mixed[] */
34 private array $parameters = [];
35
36 /**
37 * Map of LOB parameter positions to the tuples containing reference to the variable bound to the driver statement
38 * and the temporary file handle bound to the underlying statement
39 *
40 * @var array<int,string|resource|null>
41 */
42 private array $lobs = [];
43
44 /**
45 * @internal The statement can be only instantiated by its driver connection.
46 *
47 * @param resource $stmt
48 */
49 public function __construct(private readonly mixed $stmt)
50 {
51 }
52
53 public function bindValue(int|string $param, mixed $value, ParameterType $type): void
54 {
55 assert(is_int($param));
56
57 switch ($type) {
58 case ParameterType::INTEGER:
59 $this->bind($param, $value, DB2_PARAM_IN, DB2_LONG);
60 break;
61
62 case ParameterType::LARGE_OBJECT:
63 $this->lobs[$param] = &$value;
64 break;
65
66 default:
67 $this->bind($param, $value, DB2_PARAM_IN, DB2_CHAR);
68 break;
69 }
70 }
71
72 /** @throws Exception */
73 private function bind(int $position, mixed &$variable, int $parameterType, int $dataType): void
74 {
75 $this->parameters[$position] =& $variable;
76
77 if (! db2_bind_param($this->stmt, $position, '', $parameterType, $dataType)) {
78 throw StatementError::new($this->stmt);
79 }
80 }
81
82 public function execute(): Result
83 {
84 $handles = $this->bindLobs();
85
86 $result = @db2_execute($this->stmt, $this->parameters);
87
88 foreach ($handles as $handle) {
89 fclose($handle);
90 }
91
92 $this->lobs = [];
93
94 if ($result === false) {
95 throw StatementError::new($this->stmt);
96 }
97
98 return new Result($this->stmt);
99 }
100
101 /**
102 * @return list<resource>
103 *
104 * @throws Exception
105 */
106 private function bindLobs(): array
107 {
108 $handles = [];
109
110 foreach ($this->lobs as $param => $value) {
111 if (is_resource($value)) {
112 $handle = $handles[] = $this->createTemporaryFile();
113 $path = stream_get_meta_data($handle)['uri'];
114
115 $this->copyStreamToStream($value, $handle);
116
117 $this->bind($param, $path, DB2_PARAM_FILE, DB2_BINARY);
118 } else {
119 $this->bind($param, $value, DB2_PARAM_IN, DB2_CHAR);
120 }
121
122 unset($value);
123 }
124
125 return $handles;
126 }
127
128 /**
129 * @return resource
130 *
131 * @throws Exception
132 */
133 private function createTemporaryFile()
134 {
135 $handle = @tmpfile();
136
137 if ($handle === false) {
138 throw CannotCreateTemporaryFile::new(error_get_last());
139 }
140
141 return $handle;
142 }
143
144 /**
145 * @param resource $source
146 * @param resource $target
147 *
148 * @throws Exception
149 */
150 private function copyStreamToStream($source, $target): void
151 {
152 if (@stream_copy_to_stream($source, $target) === false) {
153 throw CannotCopyStreamToStream::new(error_get_last());
154 }
155 }
156}