1--TEST-- 2API vs. SQL LAST_INSERT_ID() 3--SKIPIF-- 4<?php 5 require_once('skipif.inc'); 6 require_once('skipifconnectfailure.inc'); 7?> 8--FILE-- 9<?php 10 /* 11 CAUTION: the insert_id() API call is not supposed to return 12 the same value as a call to the LAST_INSERT_ID() SQL function. 13 It is not necessarily a bug if API and SQL function return different 14 values. Check the MySQL C API reference manual for details. 15 */ 16 require_once("connect.inc"); 17 18 function get_sql_id($link) { 19 if (!($res = $link->query("SELECT LAST_INSERT_ID() AS _id"))) { 20 printf("[003] [%d] %s\n", $link->errno, $link->error); 21 return NULL; 22 } 23 $row = $res->fetch_assoc(); 24 $res->close(); 25 26 return $row['_id']; 27 } 28 29 if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) 30 printf("[001] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n", 31 $host, $user, $db, $port, $socket); 32 33 if (!$link->query("DROP TABLE IF EXISTS test") || 34 !$link->query("CREATE TABLE test (id INT auto_increment, label varchar(10) not null, PRIMARY KEY (id)) ENGINE=MyISAM") || 35 !$link->query("INSERT INTO test (id, label) VALUES (null, 'a')")) { 36 printf("[002] [%d] %s\n", $link->errno, $link->error); 37 } 38 39 $api_id = $link->insert_id; 40 $sql_id = get_sql_id($link); 41 printf("API: %d, SQL: %d\n", $api_id, $sql_id); 42 43 if ($api_id < 1) 44 printf("[004] Expecting id > 0 got %d, [%d] %s\n", $api_id, $link->errno, $link->error) ; 45 if ($api_id != $sql_id) 46 printf("[005] SQL id %d should be equal to API id %d\n", $sql_id, $api_id); 47 48 // Not an INSERT, API value must become 0 49 if (!($res = $link->query("SELECT 1 FROM DUAL"))) 50 printf("[006] [%d] %s\n", $link->errno, $link->error); 51 else 52 $res->close(); 53 54 $api_id = $link->insert_id; 55 $new_sql_id = get_sql_id($link); 56 if (0 !== $api_id) { 57 printf("[007] API id should have been reset to 0 because previous query was SELECT, got API %d, SQL %d\n", 58 $api_id, $new_sql_id); 59 } 60 if ($new_sql_id != $sql_id) { 61 printf("[008] The servers LAST_INSERT_ID() changed unexpectedly from %d to %d\n", $sql_id, $new_sql_id); 62 } 63 64 // Insert fails, LAST_INSERT_ID shall not change, API shall return 0 65 if ($link->query("INSERT INTO test (id, label) VALUES (null, null)")) { 66 printf("[009] The INSERT did not fail as planned, [%d] %s\n", $link->errno, $link->error); 67 } 68 $api_id = $link->insert_id; 69 $new_sql_id = get_sql_id($link); 70 71 if (0 !== $api_id) { 72 printf("[010] API id should have been reset to 0 because previous query was SELECT, got API %d, SQL %d\n", 73 $api_id, $new_sql_id); 74 } 75 if ($new_sql_id != $sql_id) { 76 printf("[011] The servers LAST_INSERT_ID() changed unexpectedly from %d to %d\n", $sql_id, $new_sql_id); 77 } 78 79 // Sequence counter pattern... 80 if (!$link->query("UPDATE test SET id=LAST_INSERT_ID(id+1)")) 81 printf("[012] [%d] %s\n", $link->errno, $link->error); 82 83 $api_id = $link->insert_id; 84 $new_sql_id = get_sql_id($link); 85 if ($api_id < 1) 86 printf("[013] Expecting id > 0 got %d, [%d] %s\n", $api_id, $link->errno, $link->error) ; 87 if ($api_id != $new_sql_id) 88 printf("[014] SQL id %d should be equal to API id %d\n", $new_sql_id, $api_id); 89 if ($sql_id == $new_sql_id) 90 printf("[015] SQL id %d should have had changed, got %d\n", $sql_id, $new_sql_id); 91 92 $sql_id = $new_sql_id; 93 94 // Not an INSERT (after UPDATE), API value must become 0 95 if (!$link->query("SET @myvar=1")) 96 printf("[016] [%d] %s\n", $link->errno, $link->error); 97 98 $api_id = $link->insert_id; 99 $new_sql_id = get_sql_id($link); 100 if (0 !== $api_id) { 101 printf("[017] API id should have been reset to 0 because previous query was SET, got API %d, SQL %d\n", 102 $api_id, $new_sql_id); 103 } 104 if ($new_sql_id != $sql_id) { 105 printf("[018] The servers LAST_INSERT_ID() changed unexpectedly from %d to %d\n", $sql_id, $new_sql_id); 106 } 107 108 if (!$link->query("INSERT INTO test(id, label) VALUES (LAST_INSERT_ID(id + 1), 'b')")) 109 printf("[019] [%d] %s\n", $link->errno, $link->error); 110 111 $api_id = $link->insert_id; 112 $sql_id = get_sql_id($link); 113 if ($api_id != $sql_id) 114 printf("[020] SQL id %d should be equal to API id %d\n", $sql_id, $api_id); 115 116 if (!$link->query("INSERT INTO test(label) VALUES ('c')")) 117 printf("[021] [%d] %s\n", $link->errno, $link->error); 118 119 $api_id = $link->insert_id; 120 $sql_id = get_sql_id($link); 121 if ($api_id != $sql_id) 122 printf("[022] SQL id %d should be equal to API id %d\n", $sql_id, $api_id); 123 124 if (!($res = $link->query("SELECT id, label FROM test ORDER BY id ASC"))) 125 printf("[023] [%d] %s\n", $link->errno, $link->error); 126 127 printf("Dumping table contents before INSERT...SELECT experiments...\n"); 128 while ($row = $res->fetch_assoc()) { 129 printf("id = %d, label = '%s'\n", $row['id'], $row['label']); 130 } 131 $res->close(); 132 133 if (!$link->query("INSERT INTO test(label) SELECT CONCAT(label, id) FROM test ORDER BY id ASC")) 134 printf("[024] [%d] %s\n", $link->errno, $link->error); 135 136 $api_id = $link->insert_id; 137 $sql_id = get_sql_id($link); 138 if ($api_id != $sql_id) 139 printf("[025] SQL id %d should be equal to API id %d\n", $sql_id, $api_id); 140 141 if ($link->query("INSERT INTO test(id, label) SELECT id, CONCAT(label, id) FROM test ORDER BY id ASC")) 142 printf("[026] INSERT should have failed because of duplicate PK value, [%d] %s\n", $link->errno, $link->error); 143 144 $api_id = $link->insert_id; 145 $new_sql_id = get_sql_id($link); 146 if (0 !== $api_id) { 147 printf("[027] API id should have been reset to 0 because previous query failed, got API %d, SQL %d\n", 148 $api_id, $new_sql_id); 149 } 150 if ($new_sql_id != $sql_id) { 151 printf("[028] The servers LAST_INSERT_ID() changed unexpectedly from %d to %d\n", $sql_id, $new_sql_id); 152 } 153 154 /* API insert id will be 101 because of UPDATE, SQL unchanged */ 155 if (!$link->query(sprintf("INSERT INTO test(id, label) VALUES (%d, 'z') ON DUPLICATE KEY UPDATE id = 101", $sql_id) )) 156 printf("[029] [%d] %s\n", $link->errno, $link->error); 157 158 $api_id = $link->insert_id; 159 $new_sql_id = get_sql_id($link); 160 if ($api_id != 101) 161 printf("[030] API id should be %d got %d\n", $sql_id, $api_id); 162 if ($new_sql_id != $sql_id) { 163 printf("[031] The servers LAST_INSERT_ID() changed unexpectedly from %d to %d\n", $sql_id, $new_sql_id); 164 } 165 166 if (!($res = $link->query("SELECT id, label FROM test ORDER BY id ASC"))) 167 printf("[032] [%d] %s\n", $link->errno, $link->error); 168 169 printf("Dumping table contents after INSERT...SELECT...\n"); 170 while ($row = $res->fetch_assoc()) { 171 printf("id = %d, label = '%s'\n", $row['id'], $row['label']); 172 } 173 $res->close(); 174 175 print "done!"; 176?> 177--CLEAN-- 178<?php 179 require_once("clean_table.inc"); 180?> 181--EXPECTF-- 182API: %d, SQL: %d 183Dumping table contents before INSERT...SELECT experiments... 184id = %d, label = 'b' 185id = %d, label = 'a' 186id = %d, label = 'c' 187Dumping table contents after INSERT...SELECT... 188id = %d, label = 'b' 189id = %d, label = 'a' 190id = %d, label = 'c' 191id = %d, label = 'a%d' 192id = %d, label = 'c%d' 193id = 101, label = 'b%d' 194done! 195