xref: /PHP-7.4/ext/pdo/tests/pdo_018.phpt (revision 26dfce7f)
1--TEST--
2PDO Common: serializing
3--SKIPIF--
4<?php
5if (!extension_loaded('pdo')) die('skip');
6$dir = getenv('REDIR_TEST_DIR');
7if (false == $dir) die('skip no driver');
8require_once $dir . 'pdo_test.inc';
9PDOTest::skip();
10?>
11--FILE--
12<?php
13if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
14require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
15$db = PDOTest::factory();
16
17class TestBase implements Serializable
18{
19	public    $BasePub = 'Public';
20	protected $BasePro = 'Protected';
21	private   $BasePri = 'Private';
22
23	function serialize()
24	{
25		$serialized = array();
26		foreach($this as $prop => $val) {
27			$serialized[$prop] = $val;
28		}
29		$serialized = serialize($serialized);
30		echo __METHOD__ . "() = '$serialized'\n";
31		return $serialized;
32	}
33
34	function unserialize($serialized)
35	{
36		echo __METHOD__ . "($serialized)\n";
37		foreach(unserialize($serialized) as $prop => $val) {
38			$this->$prop = '#'.$val;
39		}
40		return true;
41	}
42}
43
44class TestDerived extends TestBase
45{
46	public    $BasePub    = 'DerivedPublic';
47	protected $BasePro    = 'DerivdeProtected';
48	public    $DerivedPub = 'Public';
49	protected $DerivedPro = 'Protected';
50	private   $DerivedPri = 'Private';
51
52	function serialize()
53	{
54		echo __METHOD__ . "()\n";
55		return TestBase::serialize();
56	}
57
58	function unserialize($serialized)
59	{
60		echo __METHOD__ . "()\n";
61		return TestBase::unserialize($serialized);
62	}
63}
64
65class TestLeaf extends TestDerived
66{
67}
68
69$db->exec('CREATE TABLE classtypes(id int NOT NULL PRIMARY KEY, name VARCHAR(20) NOT NULL UNIQUE)');
70$db->exec('INSERT INTO classtypes VALUES(0, \'stdClass\')');
71$db->exec('INSERT INTO classtypes VALUES(1, \'TestBase\')');
72$db->exec('INSERT INTO classtypes VALUES(2, \'TestDerived\')');
73
74switch ($db->getAttribute(PDO::ATTR_DRIVER_NAME)) {
75  case 'dblib':
76    // environment settings can influence how the table is created if specifics are missing
77    // https://msdn.microsoft.com/en-us/library/ms174979.aspx#Nullability Rules Within a Table Definition
78    $sql = 'CREATE TABLE test(id int NOT NULL PRIMARY KEY, classtype int NULL, val VARCHAR(255) NULL)';
79    break;
80  default:
81    $sql = 'CREATE TABLE test(id int NOT NULL PRIMARY KEY, classtype int, val VARCHAR(255))';
82    break;
83}
84$db->exec($sql);
85
86$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
87
88var_dump($db->query('SELECT COUNT(*) FROM classtypes')->fetchColumn());
89var_dump($db->query('SELECT id, name FROM classtypes ORDER by id')->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_UNIQUE));
90
91$objs = array();
92$objs[0] = new stdClass;
93$objs[1] = new TestBase;
94$objs[2] = new TestDerived;
95$objs[3] = new TestLeaf;
96
97$stmt = $db->prepare('SELECT id FROM classtypes WHERE name=:cname');
98$stmt->bindParam(':cname', $cname);
99
100$ctypes = array();
101
102foreach($objs as $obj)
103{
104	$cname = get_class($obj);
105	$ctype = NULL; /* set default for non stored class name */
106	$stmt->execute();
107	$stmt->bindColumn('id', $ctype);
108	$stmt->fetch(PDO::FETCH_BOUND);
109	$ctypes[$cname] = $ctype;
110}
111
112echo "===TYPES===\n";
113var_dump($ctypes);
114
115unset($stmt);
116
117echo "===INSERT===\n";
118$stmt = $db->prepare('INSERT INTO test VALUES(:id, :classtype, :val)');
119$stmt->bindParam(':id', $idx);
120$stmt->bindParam(':classtype', $ctype);
121$stmt->bindParam(':val', $val);
122
123foreach($objs as $idx => $obj)
124{
125	$ctype = $ctypes[get_class($obj)];
126	if (method_exists($obj, 'serialize'))
127	{
128		$val = $obj->serialize();
129	}
130	else
131	{
132		$val = '';
133	}
134	$stmt->execute();
135}
136
137unset($stmt);
138
139echo "===DATA===\n";
140$res = $db->query('SELECT test.val FROM test')->fetchAll(PDO::FETCH_COLUMN);
141
142switch ($db->getAttribute(PDO::ATTR_DRIVER_NAME)) {
143	case 'dblib':
144		// map whitespace (from early TDS versions) to empty string so the test doesn't diff
145		if ($res[0] === ' ') {
146			$res[0] = '';
147		}
148		break;
149
150	case 'oci':
151		// map NULL to empty string so the test doesn't diff
152		if ($res[0] === null) {
153			$res[0] = '';
154		}
155		break;
156}
157var_dump($res);
158
159echo "===FAILURE===\n";
160try
161{
162	$db->query('SELECT classtypes.name AS name, test.val AS val FROM test LEFT JOIN classtypes ON test.classtype=classtypes.id')->fetchAll(PDO::FETCH_CLASS|PDO::FETCH_CLASSTYPE|PDO::FETCH_SERIALIZE, 'TestLeaf', array());
163}
164catch (PDOException $e)
165{
166	echo 'Exception:';
167	echo $e->getMessage()."\n";
168}
169
170echo "===COUNT===\n";
171var_dump($db->query('SELECT COUNT(*) FROM test LEFT JOIN classtypes ON test.classtype=classtypes.id WHERE (classtypes.id IS NULL OR classtypes.id > 0)')->fetchColumn());
172
173echo "===DATABASE===\n";
174$stmt = $db->prepare('SELECT classtypes.name AS name, test.val AS val FROM test LEFT JOIN classtypes ON test.classtype=classtypes.id WHERE (classtypes.id IS NULL OR classtypes.id > 0)');
175
176$stmt->execute();
177var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
178
179echo "===FETCHCLASS===\n";
180$stmt->execute();
181var_dump($stmt->fetchAll(PDO::FETCH_CLASS|PDO::FETCH_CLASSTYPE|PDO::FETCH_SERIALIZE, 'TestLeaf'));
182
183
184?>
185--EXPECTF--
186string(1) "3"
187array(3) {
188  [0]=>
189  string(8) "stdClass"
190  [1]=>
191  string(8) "TestBase"
192  [2]=>
193  string(11) "TestDerived"
194}
195===TYPES===
196array(4) {
197  ["stdClass"]=>
198  string(1) "0"
199  ["TestBase"]=>
200  string(1) "1"
201  ["TestDerived"]=>
202  string(1) "2"
203  ["TestLeaf"]=>
204  NULL
205}
206===INSERT===
207TestBase::serialize() = 'a:3:{s:7:"BasePub";s:6:"Public";s:7:"BasePro";s:9:"Protected";s:7:"BasePri";s:7:"Private";}'
208TestDerived::serialize()
209TestBase::serialize() = 'a:5:{s:7:"BasePub";s:13:"DerivedPublic";s:7:"BasePro";s:16:"DerivdeProtected";s:10:"DerivedPub";s:6:"Public";s:10:"DerivedPro";s:9:"Protected";s:7:"BasePri";s:7:"Private";}'
210TestDerived::serialize()
211TestBase::serialize() = 'a:5:{s:7:"BasePub";s:13:"DerivedPublic";s:7:"BasePro";s:16:"DerivdeProtected";s:10:"DerivedPub";s:6:"Public";s:10:"DerivedPro";s:9:"Protected";s:7:"BasePri";s:7:"Private";}'
212===DATA===
213array(4) {
214  [0]=>
215  string(0) ""
216  [1]=>
217  string(91) "a:3:{s:7:"BasePub";s:6:"Public";s:7:"BasePro";s:9:"Protected";s:7:"BasePri";s:7:"Private";}"
218  [2]=>
219  string(172) "a:5:{s:7:"BasePub";s:13:"DerivedPublic";s:7:"BasePro";s:16:"DerivdeProtected";s:10:"DerivedPub";s:6:"Public";s:10:"DerivedPro";s:9:"Protected";s:7:"BasePri";s:7:"Private";}"
220  [3]=>
221  string(172) "a:5:{s:7:"BasePub";s:13:"DerivedPublic";s:7:"BasePro";s:16:"DerivdeProtected";s:10:"DerivedPub";s:6:"Public";s:10:"DerivedPro";s:9:"Protected";s:7:"BasePri";s:7:"Private";}"
222}
223===FAILURE===
224Exception:SQLSTATE[HY000]: General error: cannot unserialize class
225===COUNT===
226string(1) "3"
227===DATABASE===
228array(3) {
229  [0]=>
230  array(2) {
231    ["name"]=>
232    string(8) "TestBase"
233    ["val"]=>
234    string(91) "a:3:{s:7:"BasePub";s:6:"Public";s:7:"BasePro";s:9:"Protected";s:7:"BasePri";s:7:"Private";}"
235  }
236  [1]=>
237  array(2) {
238    ["name"]=>
239    string(11) "TestDerived"
240    ["val"]=>
241    string(172) "a:5:{s:7:"BasePub";s:13:"DerivedPublic";s:7:"BasePro";s:16:"DerivdeProtected";s:10:"DerivedPub";s:6:"Public";s:10:"DerivedPro";s:9:"Protected";s:7:"BasePri";s:7:"Private";}"
242  }
243  [2]=>
244  array(2) {
245    ["name"]=>
246    NULL
247    ["val"]=>
248    string(172) "a:5:{s:7:"BasePub";s:13:"DerivedPublic";s:7:"BasePro";s:16:"DerivdeProtected";s:10:"DerivedPub";s:6:"Public";s:10:"DerivedPro";s:9:"Protected";s:7:"BasePri";s:7:"Private";}"
249  }
250}
251===FETCHCLASS===
252TestBase::unserialize(a:3:{s:7:"BasePub";s:6:"Public";s:7:"BasePro";s:9:"Protected";s:7:"BasePri";s:7:"Private";})
253TestDerived::unserialize()
254TestBase::unserialize(a:5:{s:7:"BasePub";s:13:"DerivedPublic";s:7:"BasePro";s:16:"DerivdeProtected";s:10:"DerivedPub";s:6:"Public";s:10:"DerivedPro";s:9:"Protected";s:7:"BasePri";s:7:"Private";})
255TestDerived::unserialize()
256TestBase::unserialize(a:5:{s:7:"BasePub";s:13:"DerivedPublic";s:7:"BasePro";s:16:"DerivdeProtected";s:10:"DerivedPub";s:6:"Public";s:10:"DerivedPro";s:9:"Protected";s:7:"BasePri";s:7:"Private";})
257array(3) {
258  [0]=>
259  object(TestBase)#%d (3) {
260    ["BasePub"]=>
261    string(7) "#Public"
262    ["BasePro":protected]=>
263    string(10) "#Protected"
264    ["BasePri":"TestBase":private]=>
265    string(8) "#Private"
266  }
267  [1]=>
268  object(TestDerived)#%d (6) {
269    ["BasePub"]=>
270    string(14) "#DerivedPublic"
271    ["BasePro":protected]=>
272    string(17) "#DerivdeProtected"
273    ["DerivedPub"]=>
274    string(7) "#Public"
275    ["DerivedPro":protected]=>
276    string(10) "#Protected"
277    ["DerivedPri":"TestDerived":private]=>
278    string(7) "Private"
279    ["BasePri":"TestBase":private]=>
280    string(8) "#Private"
281  }
282  [2]=>
283  object(TestLeaf)#%d (6) {
284    ["BasePub"]=>
285    string(14) "#DerivedPublic"
286    ["BasePro":protected]=>
287    string(17) "#DerivdeProtected"
288    ["DerivedPub"]=>
289    string(7) "#Public"
290    ["DerivedPro":protected]=>
291    string(10) "#Protected"
292    ["DerivedPri":"TestDerived":private]=>
293    string(7) "Private"
294    ["BasePri":"TestBase":private]=>
295    string(8) "#Private"
296  }
297}
298