1 /// Exceptions defined by mysql-native. 2 module mysql.exceptions; 3 4 import std.algorithm; 5 import mysql.protocol.packets; 6 7 /++ 8 An exception type to distinguish exceptions thrown by this package. 9 +/ 10 class MYX: Exception 11 { 12 this(string msg, string file = __FILE__, size_t line = __LINE__) pure 13 { 14 super(msg, file, line); 15 } 16 } 17 deprecated("This has been renamed MYX") 18 alias MySQLException = MYX; 19 20 /++ 21 The server sent back a MySQL error code and message. If the server is 4.1+, 22 there should also be an ANSI/ODBC-standard SQLSTATE error code. 23 24 See_Also: https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html 25 +/ 26 class MYXReceived: MYX 27 { 28 ushort errorCode; 29 char[5] sqlState; 30 31 this(OKErrorPacket okp, string file, size_t line) pure 32 { 33 this(okp.message, okp.serverStatus, okp.sqlState, file, line); 34 } 35 36 this(string msg, ushort errorCode, char[5] sqlState, string file, size_t line) pure 37 { 38 this.errorCode = errorCode; 39 this.sqlState = sqlState; 40 super("MySQL error: " ~ msg, file, line); 41 } 42 } 43 deprecated("This has been renamed MYXReceived") 44 alias MySQLReceivedException = MYXReceived; 45 46 /++ 47 This exception is no longer used by mysql-native and will be removed 48 in an upcoming release. 49 50 Previously, this was thrown when attempting to communicate with the server 51 (ex: executing SQL or creating a new prepared statement) while the server 52 was still sending results data. Any `mysql.result.ResultRange` was required to 53 be consumed or purged before anything else was allowed to be done on the 54 connection (as per inherent limitations of the MySQL client-server protocol). 55 56 But as of mysql-native v1.1.4 (as discussed in 57 $(LINK2 https://github.com/mysql-d/mysql-native/issues/117, issue #117)), 58 this behavior was changed. Any communication with the server now purges any 59 active `mysql.result.ResultRange` automatically (See also, 60 `mysql.result.ResultRange.isValid`). As a result, this exception is never 61 thrown anymore. 62 +/ 63 deprecated("No longer thrown by mysql-native, as of v1.1.4. You can safely remove all MYXDataPending handling from your code.") 64 class MYXDataPending: MYX 65 { 66 this(string file = __FILE__, size_t line = __LINE__) pure 67 { 68 super("Data is pending on the connection. Any existing ResultRange "~ 69 "must be consumed or purged before performing any other communication "~ 70 "with the server.", file, line); 71 } 72 } 73 deprecated("No longer thrown by mysql-native, as of v1.1.4. You can safely remove all MYXDataPending handling from your code.") 74 alias MySQLDataPendingException = MYXDataPending; 75 76 /++ 77 Received invalid data from the server which violates the MySQL network protocol. 78 (Quite possibly mysql-native's fault. Please 79 $(LINK2 https://github.com/mysql-d/mysql-native/issues, file an issue) 80 if you receive this.) 81 +/ 82 class MYXProtocol: MYX 83 { 84 this(string msg, string file, size_t line) pure 85 { 86 super(msg, file, line); 87 } 88 } 89 deprecated("This has been renamed MYXProtocol") 90 alias MySQLProtocolException = MYXProtocol; 91 92 /++ 93 Thrown when attempting to use a prepared statement which had already been released. 94 +/ 95 class MYXNotPrepared: MYX 96 { 97 this(string file = __FILE__, size_t line = __LINE__) pure 98 { 99 super("The prepared statement has already been released.", file, line); 100 } 101 } 102 deprecated("This has been renamed MYXNotPrepared") 103 alias MySQLNotPreparedException = MYXNotPrepared; 104 105 /++ 106 Common base class of MYXResultRecieved and MYXNoResultRecieved. 107 108 Thrown when making the wrong choice between exec or query. 109 110 The query functions (query, queryRow, etc.) are for SQL statements 111 such as SELECT that return results (even if the result set has zero elements.) 112 113 The exec functions are for SQL statements, such as INSERT, that never return 114 result sets, but may return rowsAffected. 115 116 Using one of those functions, when the other should have been used instead, 117 results in an exception derived from this. 118 +/ 119 class MYXWrongFunction: MYX 120 { 121 this(string msg, string file = __FILE__, size_t line = __LINE__) pure 122 { 123 super(msg, file, line); 124 } 125 } 126 deprecated("This has been renamed MYXWrongFunction") 127 alias MySQLWrongFunctionException = MYXWrongFunction; 128 129 /++ 130 Thrown when a result set was returned unexpectedly. Use the query functions 131 (query, queryRow, etc.), not exec for commands that return 132 result sets (such as SELECT), even if the result set has zero elements. 133 +/ 134 class MYXResultRecieved: MYXWrongFunction 135 { 136 this(string file = __FILE__, size_t line = __LINE__) pure 137 { 138 super( 139 "A result set was returned. Use the query functions, not exec, "~ 140 "for commands that return result sets.", 141 file, line 142 ); 143 } 144 } 145 deprecated("This has been renamed MYXResultRecieved") 146 alias MySQLResultRecievedException = MYXResultRecieved; 147 148 /++ 149 Thrown when the executed query, unexpectedly, did not produce a result set. 150 Use the exec functions, not query (query, queryRow, etc.), 151 for commands that don't produce result sets (such as INSERT). 152 +/ 153 class MYXNoResultRecieved: MYXWrongFunction 154 { 155 this(string msg, string file = __FILE__, size_t line = __LINE__) pure 156 { 157 super( 158 "The executed query did not produce a result set. Use the exec "~ 159 "functions, not query, for commands that don't produce result sets.", 160 file, line 161 ); 162 } 163 } 164 deprecated("This has been renamed MYXNoResultRecieved") 165 alias MySQLNoResultRecievedException = MYXNoResultRecieved; 166 167 /++ 168 Thrown when attempting to use a range that's been invalidated. 169 In particular, when using a ResultRange after a new command 170 has been issued on the same connection. 171 +/ 172 class MYXInvalidatedRange: MYX 173 { 174 this(string msg, string file = __FILE__, size_t line = __LINE__) pure 175 { 176 super(msg, file, line); 177 } 178 } 179 deprecated("This has been renamed MYXInvalidatedRange") 180 alias MySQLInvalidatedRangeException = MYXInvalidatedRange; 181 182 debug(MYSQL_INTEGRATION_TESTS) 183 unittest 184 { 185 import std.exception; 186 import mysql.commands; 187 import mysql.prepared; 188 import mysql.test.common : scopedCn, createCn; 189 mixin(scopedCn); 190 191 cn.exec("DROP TABLE IF EXISTS `wrongFunctionException`"); 192 cn.exec("CREATE TABLE `wrongFunctionException` ( 193 `val` INTEGER 194 ) ENGINE=InnoDB DEFAULT CHARSET=utf8"); 195 196 immutable insertSQL = "INSERT INTO `wrongFunctionException` VALUES (1), (2)"; 197 immutable selectSQL = "SELECT * FROM `wrongFunctionException`"; 198 Prepared preparedInsert; 199 Prepared preparedSelect; 200 int queryTupleResult; 201 assertNotThrown!MYXWrongFunction(cn.exec(insertSQL)); 202 assertNotThrown!MYXWrongFunction(cn.querySet(selectSQL)); 203 assertNotThrown!MYXWrongFunction(cn.query(selectSQL).each()); 204 assertNotThrown!MYXWrongFunction(cn.queryRowTuple(selectSQL, queryTupleResult)); 205 assertNotThrown!MYXWrongFunction(preparedInsert = cn.prepare(insertSQL)); 206 assertNotThrown!MYXWrongFunction(preparedSelect = cn.prepare(selectSQL)); 207 assertNotThrown!MYXWrongFunction(preparedInsert.exec()); 208 assertNotThrown!MYXWrongFunction(preparedSelect.querySet()); 209 assertNotThrown!MYXWrongFunction(preparedSelect.query().each()); 210 assertNotThrown!MYXWrongFunction(preparedSelect.queryRowTuple(queryTupleResult)); 211 212 assertThrown!MYXResultRecieved(cn.exec(selectSQL)); 213 assertThrown!MYXNoResultRecieved(cn.querySet(insertSQL)); 214 assertThrown!MYXNoResultRecieved(cn.query(insertSQL).each()); 215 assertThrown!MYXNoResultRecieved(cn.queryRowTuple(insertSQL, queryTupleResult)); 216 assertThrown!MYXResultRecieved(preparedSelect.exec()); 217 assertThrown!MYXNoResultRecieved(preparedInsert.querySet()); 218 assertThrown!MYXNoResultRecieved(preparedInsert.query().each()); 219 assertThrown!MYXNoResultRecieved(preparedInsert.queryRowTuple(queryTupleResult)); 220 }