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        'VARBINARY(127) DEFAULT NULL' => 'BINARY',
64        'BLOB'	=> 'BLOB BINARY',
65        'TINYBLOB'	=> 'BLOB BINARY',
66        'MEDIUMBLOB'	=> 'BLOB BINARY',
67        'LONGBLOB'	=> 'BLOB BINARY',
68        'TEXT'	=> 'BLOB',
69        'TINYTEXT'	=> 'BLOB',
70        'MEDIUMTEXT'	=> 'BLOB',
71        'LONGTEXT'	=> 'BLOB',
72        'SET("one", "two")'	=> 'SET',
73        'SET("one", "two") NOT NULL'	=> 'NOT_NULL SET NO_DEFAULT_VALUE',
74        'SET("one", "two") NOT NULL DEFAULT "one"'	=> 'NOT_NULL SET',
75        'ENUM("one", "two")'	=> 'ENUM',
76        'ENUM("one", "two") NOT NULL' => 'NOT_NULL ENUM NO_DEFAULT_VALUE',
77        'ENUM("one", "two") NOT NULL DEFAULT "one"' => 'NOT_NULL ENUM',
78        'TINYINT UNIQUE' => 'UNIQUE_KEY NUM PART_KEY',
79        'SMALLINT UNIQUE' => 'UNIQUE_KEY NUM PART_KEY',
80        'MEDIUMINT UNIQUE DEFAULT 1' => 'UNIQUE_KEY NUM PART_KEY',
81        'BIGINT UNSIGNED UNIQUE DEFAULT 100' => 'UNIQUE_KEY UNSIGNED NUM PART_KEY',
82        'BIT' => 'UNSIGNED',
83        'VARCHAR(2) NOT NULL PRIMARY KEY' => 'NOT_NULL PRI_KEY NO_DEFAULT_VALUE PART_KEY'
84    );
85
86
87
88    function checkFlags($reported_flags, $expected_flags, $flags) {
89        $found_flags = $unexpected_flags = '';
90        foreach ($flags as $code => $name) {
91            if ($reported_flags >= $code) {
92                $reported_flags -= $code;
93                $found_flags .= $name . ' ';
94                if (stristr($expected_flags, $name)) {
95                    $expected_flags = trim(str_ireplace($name, '', $expected_flags));
96                } else {
97                    $unexpected_flags .= $name . ' ';
98                }
99            }
100        }
101
102        return array($expected_flags, $unexpected_flags, $found_flags);
103    }
104
105    if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
106        printf("[001] [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
107
108    foreach ($columns as $column_def => $expected_flags) {
109        if (!mysqli_query($link, 'DROP TABLE IF EXISTS test')) {
110            printf("[002] %s [%d] %s\n", $column_def,
111                mysqli_errno($link), mysqli_error($link));
112            continue;
113        }
114
115        $create = sprintf('CREATE TABLE test(id INT, col1 %s)', $column_def);
116        if (!mysqli_query($link, $create)) {
117            // Server might not support it - skip
118            continue;
119        }
120
121        if (!$res = mysqli_query($link, 'SELECT * FROM test')) {
122            printf("[003] Can't select from table, %s [%d] %s\n", $column_def,
123                mysqli_errno($link), mysqli_error($link));
124            continue;
125        }
126
127        $field = mysqli_fetch_field_direct($res, 1);
128        if (!is_object($field)) {
129            printf("[004] Fetching the meta data failed, %s [%d] %s\n", $column_def,
130                mysqli_errno($link), mysqli_error($link));
131            continue;
132        }
133        if ($field->name != 'col1') {
134            printf("[005] Field information seems wrong, %s [%d] %s\n", $column_def,
135                mysqli_errno($link), mysqli_error($link));
136            continue;
137        }
138
139        /*
140        TODO
141        Unfortunately different server versions give you slightly different
142        results.The test does not yet fully reflect all server changes/bugs etc.
143        */
144        switch ($column_def) {
145            case 'INT UNSIGNED NOT NULL':
146            case 'INT NOT NULL':
147            case 'CHAR(1) NOT NULL':
148            case 'SET("one", "two") NOT NULL':
149            case 'ENUM("one", "two") NOT NULL':
150                $version = mysqli_get_server_version($link);
151                if ($version < 50000) {
152                    // TODO - check exact version!
153                    $expected_flags = trim(str_replace('NO_DEFAULT_VALUE', '', $expected_flags));
154                }
155                break;
156
157            case 'BIT':
158                $version = mysqli_get_server_version($link);
159                if (($version <= 50114 && $version > 50100) || ($version == 50200)) {
160                    // TODO - check exact version!
161                    $expected_flags = trim(str_replace('UNSIGNED', '', $expected_flags));
162                }
163
164            default:
165                break;
166        }
167
168        list($missing_flags, $unexpected_flags, $flags_found) = checkFlags($field->flags, $expected_flags, $flags);
169        if ($unexpected_flags) {
170            printf("[006] Found unexpected flags '%s' for %s, found '%s' with MySQL %s'\n",
171                $unexpected_flags, $column_def, $flags_found, mysqli_get_server_version($link));
172        }
173        if ($missing_flags) {
174            printf("[007] The flags '%s' have not been reported for %s, found '%s'\n",
175                $missing_flags, $column_def, $flags_found);
176            var_dump($create);
177            var_dump(mysqli_get_server_version($link));
178            die($missing_flags);
179        }
180
181        mysqli_free_result($res);
182    }
183
184    if (!mysqli_query($link, 'DROP TABLE IF EXISTS test')) {
185        printf("[008] %s [%d] %s\n", $column_def,
186            mysqli_errno($link), mysqli_error($link));
187    }
188
189    $column_def = array('col1 CHAR(1)', 'col2 CHAR(2)','INDEX idx_col1_col2(col1, col2)');
190    $expected_flags = array('col1' => 'MULTIPLE_KEY PART_KEY', 'col2' => 'PART_KEY');
191    $create = 'CREATE TABLE test(id INT, ';
192    foreach ($column_def as $k => $v) {
193        $create .= sprintf('%s, ', $v);
194    }
195    $create = sprintf('%s)', substr($create, 0, -2));
196
197    if (mysqli_query($link, $create)) {
198        if (!$res = mysqli_query($link, 'SELECT * FROM test')) {
199            printf("[009] Cannot run SELECT, [%d] %s\n",
200                mysqli_errno($link), mysqli_error($link));
201        }
202        // id column - skip it
203        $field = mysqli_fetch_field($res);
204        while ($field = mysqli_fetch_field($res)) {
205            if (!isset($expected_flags[$field->name])) {
206                printf("[010] Found unexpected field '%s'\n", $field->name);
207            }
208            list($missing_flags, $unexpected_flags, $flags_found) = checkFlags($field->flags, $expected_flags[$field->name], $flags);
209            if ($unexpected_flags)
210                printf("[011] Found unexpected flags '%s' for %s, found '%s'\n",
211                    $unexpected_flags, $field->name, $flags_found);
212            if ($missing_flags)
213                printf("[012] The flags '%s' have not been reported for %s, found '%s'\n",
214                    $missing_flags, $field->name, $flags_found);
215        }
216    }
217
218    mysqli_close($link);
219    print "done!";
220?>
221--CLEAN--
222<?php
223    require_once("clean_table.inc");
224?>
225--EXPECT--
226done!
227