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