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