1--TEST--
2mysqli_fetch_field() - flags/field->flags
3--SKIPIF--
4<?php
5require_once('skipif.inc');
6require_once('skipifemb.inc');
7require_once('skipifconnectfailure.inc');
8
9require_once('connect.inc');
10if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
11		die(printf("skip: [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));
12
13if (mysqli_get_server_version($link) < 50041)
14	die("skip: Due to many MySQL Server differences, the test requires 5.0.41+");
15
16mysqli_close($link);
17?>
18--FILE--
19<?php
20	require_once("connect.inc");
21
22/* TODO: mysqli.c needs to export a few more constants - see all the defined() calls! */
23
24	$flags = array(
25		MYSQLI_NOT_NULL_FLAG => 'NOT_NULL',
26		MYSQLI_PRI_KEY_FLAG => 'PRI_KEY',
27		MYSQLI_UNIQUE_KEY_FLAG => 'UNIQUE_KEY',
28		MYSQLI_MULTIPLE_KEY_FLAG => 'MULTIPLE_KEY',
29		MYSQLI_BLOB_FLAG => 'BLOB',
30		MYSQLI_UNSIGNED_FLAG	=> 'UNSIGNED',
31		MYSQLI_ZEROFILL_FLAG => 'ZEROFILL',
32		MYSQLI_AUTO_INCREMENT_FLAG => 'AUTO_INCREMENT',
33		MYSQLI_TIMESTAMP_FLAG	=> 'TIMESTAMP',
34		MYSQLI_SET_FLAG	=> 'SET',
35		MYSQLI_NUM_FLAG => 'NUM',
36		MYSQLI_PART_KEY_FLAG => 'PART_KEY',
37		// MYSQLI_GROUP_FLAG => 'MYSQLI_GROUP_FLAG' - internal usage only
38		(defined('MYSQLI_NO_DEFAULT_VALUE_FLAG') ? MYSQLI_NO_DEFAULT_VALUE_FLAG : 4096) => 'NO_DEFAULT_VALUE',
39		(defined('MYSQLI_BINARY_FLAG') ? MYSQLI_BINARY_FLAG : 128) => 'BINARY',
40		(defined('MYSQLI_ENUM_FLAG') ? MYSQLI_ENUM_FLAG : 256) => 'ENUM',
41		// MYSQLI_BINCMP_FLAG
42	);
43
44	// 5.1.24 / 6.0.4+
45	if (defined('MYSQLI_ON_UPDATE_NOW'))
46		$flags[MYSQLI_ON_UPDATE_NOW] = 'ON_UPDATE_NOW';
47	else
48		$flags[8192] = 'ON_UPDATE_NOW';
49
50	krsort($flags);
51
52	$columns = array(
53		'INT DEFAULT NULL' => 'NUM',
54		'INT NOT NULL' => 'NOT_NULL NO_DEFAULT_VALUE NUM',
55		'INT NOT NULL DEFAULT 1' => 'NOT_NULL NUM',
56		'INT UNSIGNED DEFAULT NULL' => 'UNSIGNED NUM',
57		'INT UNSIGNED NOT NULL'	=> 'NOT_NULL UNSIGNED NO_DEFAULT_VALUE NUM',
58		'INT UNSIGNED NOT NULL DEFAULT 1' => 'NOT_NULL UNSIGNED NUM',
59		'INT UNSIGNED ZEROFILL DEFAULT NULL' => 'UNSIGNED ZEROFILL NUM',
60		'INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY' => 'NOT_NULL PRI_KEY UNSIGNED AUTO_INCREMENT NUM PART_KEY',
61		'CHAR(1) DEFAULT NULL'	=> '',
62		'CHAR(1) NOT NULL' => 'NOT_NULL NO_DEFAULT_VALUE',
63		'TIMESTAMP NOT NULL' => 'NOT_NULL UNSIGNED ZEROFILL BINARY TIMESTAMP',
64		'VARBINARY(127) DEFAULT NULL' => 'BINARY',
65		'BLOB'	=> 'BLOB BINARY',
66		'TINYBLOB'	=> 'BLOB BINARY',
67		'MEDIUMBLOB'	=> 'BLOB BINARY',
68		'LONGBLOB'	=> 'BLOB BINARY',
69		'TEXT'	=> 'BLOB',
70		'TINYTEXT'	=> 'BLOB',
71		'MEDIUMTEXT'	=> 'BLOB',
72		'LONGTEXT'	=> 'BLOB',
73		'SET("one", "two")'	=> 'SET',
74		'SET("one", "two") NOT NULL'	=> 'NOT_NULL SET NO_DEFAULT_VALUE',
75		'SET("one", "two") NOT NULL DEFAULT "one"'	=> 'NOT_NULL SET',
76		'ENUM("one", "two")'	=> 'ENUM',
77		'ENUM("one", "two") NOT NULL' => 'NOT_NULL ENUM NO_DEFAULT_VALUE',
78		'ENUM("one", "two") NOT NULL DEFAULT "one"' => 'NOT_NULL ENUM',
79		'TINYINT UNIQUE' => 'UNIQUE_KEY NUM PART_KEY',
80		'SMALLINT UNIQUE' => 'UNIQUE_KEY NUM PART_KEY',
81		'MEDIUMINT UNIQUE DEFAULT 1' => 'UNIQUE_KEY NUM PART_KEY',
82		'BIGINT UNSIGNED UNIQUE DEFAULT 100' => 'UNIQUE_KEY UNSIGNED NUM PART_KEY',
83		'BIT' => 'UNSIGNED',
84		'VARCHAR(2) NOT NULL PRIMARY KEY' => 'NOT_NULL PRI_KEY NO_DEFAULT_VALUE PART_KEY'
85	);
86
87
88
89	function checkFlags($reported_flags, $expected_flags, $flags) {
90		$found_flags = $unexpected_flags = '';
91		foreach ($flags as $code => $name) {
92			if ($reported_flags >= $code) {
93				$reported_flags -= $code;
94				$found_flags .= $name . ' ';
95				if (stristr($expected_flags, $name)) {
96					$expected_flags = trim(str_ireplace($name, '', $expected_flags));
97				} else {
98					$unexpected_flags .= $name . ' ';
99				}
100			}
101		}
102
103		return array($expected_flags, $unexpected_flags, $found_flags);
104	}
105
106	if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
107		printf("[001] [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
108
109	$is_maria_db = strpos(mysqli_get_server_info($link), "MariaDB") !== false;
110	if ($is_maria_db) {
111		$columns['TIMESTAMP NOT NULL'] = 'ON_UPDATE_NOW TIMESTAMP BINARY UNSIGNED NOT_NULL';
112	} else if (mysqli_get_server_version($link) > 50600) {
113		$columns['TIMESTAMP NOT NULL'] = 'ON_UPDATE_NOW TIMESTAMP BINARY NOT_NULL';
114	}
115
116	foreach ($columns as $column_def => $expected_flags) {
117		if (!mysqli_query($link, 'DROP TABLE IF EXISTS test')) {
118			printf("[002] %s [%d] %s\n", $column_def,
119				mysqli_errno($link), mysqli_error($link));
120			continue;
121		}
122
123		$create = sprintf('CREATE TABLE test(id INT, col1 %s)', $column_def);
124		if (!mysqli_query($link, $create)) {
125			// Server might not support it - skip
126			continue;
127		}
128
129		if (!$res = mysqli_query($link, 'SELECT * FROM test')) {
130			printf("[003] Can't select from table, %s [%d] %s\n", $column_def,
131				mysqli_errno($link), mysqli_error($link));
132			continue;
133		}
134
135		$field = mysqli_fetch_field_direct($res, 1);
136		if (!is_object($field)) {
137			printf("[004] Fetching the meta data failed, %s [%d] %s\n", $column_def,
138				mysqli_errno($link), mysqli_error($link));
139			continue;
140		}
141		if ($field->name != 'col1') {
142			printf("[005] Field information seems wrong, %s [%d] %s\n", $column_def,
143				mysqli_errno($link), mysqli_error($link));
144			continue;
145		}
146
147		/*
148		TODO
149		Unfortunately different server versions give you slightly different
150		results.The test does not yet fully reflect all server changes/bugs etc.
151		*/
152		switch ($column_def) {
153			case 'TIMESTAMP NOT NULL':
154				// http://bugs.mysql.com/bug.php?id=30081 - new flag introduced in 5.1.24/6.0.4
155				$version = mysqli_get_server_version($link);
156				if ((($version >  50122) && ($version < 60000) && ($version != 50200)) ||
157						($version >= 60004)) {
158					// new flag ON_UPDATE_NOW_FLAG (8192)
159					$expected_flags .= ' ON_UPDATE_NOW';
160				}
161				break;
162
163			case 'INT UNSIGNED NOT NULL':
164			case 'INT NOT NULL':
165			case 'CHAR(1) NOT NULL':
166			case 'SET("one", "two") NOT NULL':
167			case 'ENUM("one", "two") NOT NULL':
168				$version = mysqli_get_server_version($link);
169				if ($version < 50000) {
170					// TODO - check exact version!
171					$expected_flags = trim(str_replace('NO_DEFAULT_VALUE', '', $expected_flags));
172				}
173				break;
174
175			case 'BIT':
176				$version = mysqli_get_server_version($link);
177				if (($version <= 50114 && $version > 50100) || ($version == 50200)) {
178					// TODO - check exact version!
179					$expected_flags = trim(str_replace('UNSIGNED', '', $expected_flags));
180				}
181
182			default:
183				break;
184		}
185
186		list($missing_flags, $unexpected_flags, $flags_found) = checkFlags($field->flags, $expected_flags, $flags);
187		if ($unexpected_flags) {
188			printf("[006] Found unexpected flags '%s' for %s, found '%s' with MySQL %s'\n",
189				$unexpected_flags, $column_def, $flags_found, mysqli_get_server_version($link));
190		}
191		if ($missing_flags) {
192			printf("[007] The flags '%s' have not been reported for %s, found '%s'\n",
193				$missing_flags, $column_def, $flags_found);
194			var_dump($create);
195			var_dump(mysqli_get_server_version($link));
196			die($missing_flags);
197		}
198
199		mysqli_free_result($res);
200	}
201
202	if (!mysqli_query($link, 'DROP TABLE IF EXISTS test')) {
203		printf("[008] %s [%d] %s\n", $column_def,
204			mysqli_errno($link), mysqli_error($link));
205	}
206
207	$column_def = array('col1 CHAR(1)', 'col2 CHAR(2)','INDEX idx_col1_col2(col1, col2)');
208	$expected_flags = array('col1' => 'MULTIPLE_KEY PART_KEY', 'col2' => 'PART_KEY');
209	$create = 'CREATE TABLE test(id INT, ';
210	foreach ($column_def as $k => $v) {
211		$create .= sprintf('%s, ', $v);
212	}
213	$create = sprintf('%s)', substr($create, 0, -2));
214
215	if (mysqli_query($link, $create)) {
216		if (!$res = mysqli_query($link, 'SELECT * FROM test')) {
217			printf("[009] Cannot run SELECT, [%d] %s\n",
218				mysqli_errno($link), mysqli_error($link));
219		}
220		// id column - skip it
221		$field = mysqli_fetch_field($res);
222		while ($field = mysqli_fetch_field($res)) {
223			if (!isset($expected_flags[$field->name])) {
224				printf("[010] Found unexpected field '%s'\n", $field->name);
225			}
226			list($missing_flags, $unexpected_flags, $flags_found) = checkFlags($field->flags, $expected_flags[$field->name], $flags);
227			if ($unexpected_flags)
228				printf("[011] Found unexpected flags '%s' for %s, found '%s'\n",
229					$unexpected_flags, $field->name, $flags_found);
230			if ($missing_flags)
231				printf("[012] The flags '%s' have not been reported for %s, found '%s'\n",
232					$missing_flags, $field->name, $flags_found);
233		}
234	}
235
236	mysqli_close($link);
237	print "done!";
238?>
239--CLEAN--
240<?php
241	require_once("clean_table.inc");
242?>
243--EXPECTF--
244done!