Changeset 95
- Timestamp:
- 10/28/08 19:16:04 (4 years ago)
- Files:
-
- trunk/buildme.d (deleted)
- trunk/dbi/DBIException.d (deleted)
- trunk/dbi/Database.d (deleted)
- trunk/dbi/ErrorCode.d (modified) (1 diff)
- trunk/dbi/Exception.d (added)
- trunk/dbi/Metadata.d (deleted)
- trunk/dbi/PreparedStatement.d (deleted)
- trunk/dbi/Registry.d (deleted)
- trunk/dbi/Result.d (deleted)
- trunk/dbi/Row.d (deleted)
- trunk/dbi/SqlGen.d (deleted)
- trunk/dbi/Statement.d (deleted)
- trunk/dbi/ib (deleted)
- trunk/dbi/model (added)
- trunk/dbi/model/Database.d (added)
- trunk/dbi/model/Result.d (added)
- trunk/dbi/model/Statement.d (added)
- trunk/dbi/model/Types.d (added)
- trunk/dbi/msql (deleted)
- trunk/dbi/mssql (deleted)
- trunk/dbi/mysql/MysqlDatabase.d (modified) (1 diff)
- trunk/dbi/mysql/MysqlError.d (modified) (3 diffs)
- trunk/dbi/mysql/MysqlPreparedStatement.d (deleted)
- trunk/dbi/mysql/MysqlResult.d (modified) (1 diff)
- trunk/dbi/mysql/MysqlStatement.d (added)
- trunk/dbi/mysql/all.d (deleted)
- trunk/dbi/mysql/c (added)
- trunk/dbi/mysql/c/mysql.d (moved) (moved from trunk/dbi/mysql/imp.d) (1 diff, 1 prop)
- trunk/dbi/mysql/imp_win.d (deleted)
- trunk/dbi/odbc (deleted)
- trunk/dbi/oracle (deleted)
- trunk/dbi/pg (deleted)
- trunk/dbi/sqlite (deleted)
- trunk/docs (deleted)
- trunk/dsss.conf (modified) (2 diffs)
- trunk/test (added)
- trunk/test/mysql.d (added)
- trunk/testddbi.d (deleted)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/dbi/ErrorCode.d
r70 r95 81 81 return "Not a valid ErrorCode"; 82 82 } 83 // Bugfix for DMD 0.16283 // Return workaround 84 84 return "Not a valid ErrorCode"; 85 85 } trunk/dbi/mysql/MysqlDatabase.d
r89 r95 1 /**1 /** 2 2 * Authors: The D DBI project 3 3 * Copyright: BSD license 4 4 */ 5 5 6 module dbi.mysql.MysqlDatabase; 6 7 7 version (dbi_mysql) { 8 9 private import tango.stdc.stringz : toDString = fromStringz, toCString = toStringz; 10 private import tango.io.Console; 11 private static import tango.text.Util; 12 private static import tango.text.convert.Integer; 13 debug(UnitTest) import tango.io.Stdout; 14 15 private import dbi.Database, dbi.DBIException, dbi.Result, dbi.Row, dbi.Statement, dbi.Registry; 16 version(Windows) { 17 private import dbi.mysql.imp_win; 18 } 19 else { 20 private import dbi.mysql.imp; 21 } 22 private import dbi.mysql.MysqlError, dbi.mysql.MysqlResult; 23 24 static this() { 25 uint ver = mysql_get_client_version(); 26 if(ver < 50000) { 27 throw new Exception("Unsupported MySQL client version. Please compile using at least version 5.0 of the MySQL client libray."); 28 } 29 else if(ver < 50100) { 30 if(MYSQL_VERSION != 50000) { 31 throw new Exception("You are linking against version 5.0 of the MySQL client library but you have a build switch turned on for a different version (such as MySQL_51)."); 32 } 33 } 34 else { 35 if(MYSQL_VERSION != 50100) { 36 throw new Exception("You are linking against version 5.1 (or higher) of the MySQL client library so you need to use the build switch '-version=MySQL_51'."); 37 } 38 } 39 } 40 41 /** 42 * An implementation of Database for use with MySQL databases. 43 * 44 * Bugs: 45 * Column types aren't retrieved. 46 * 47 * See_Also: 48 * Database is the interface that this provides an implementation of. 49 */ 50 class MysqlDatabase : Database { 51 public: 52 /** 53 * Create a new instance of MysqlDatabase, but don't connect. 54 */ 55 this () { 56 connection = mysql_init(null); 57 } 58 59 /** 60 * Create a new instance of MysqlDatabase and connect to a server. 61 * 62 * See_Also: 63 * connect 64 */ 65 this (char[] params, char[] username = null, char[] password = null) { 66 this(); 67 connect(params, username, password); 68 } 69 70 /** 71 * Connect to a database on a MySQL server. 72 * 73 * Params: 74 * params = A string in the form "keyword1=value1;keyword2=value2;etc." 75 * username = The _username to _connect with. 76 * password = The _password to _connect with. 77 * 78 * Keywords: 79 * dbname = The name of the database to use. 80 * 81 * host = The host name of the database to _connect to. 82 * 83 * port = The port number to _connect to. 84 * 85 * sock = The socket to _connect to. 86 * 87 * Throws: 88 * DBIException if there was an error connecting. 89 * 90 * DBIException if port is provided but is not an integer. 91 * 92 * Examples: 93 * --- 94 * MysqlDatabase db = new MysqlDatabase(); 95 * db.connect("host=localhost;dbname=test", "username", "password"); 96 * --- 97 */ 98 override void connect (char[] params, char[] username = null, char[] password = null) { 99 char[] host = "localhost"; 100 char[] dbname = "test"; 101 char[] sock = null; 102 uint port = 0; 103 104 void parseKeywords () { 105 char[][char[]] keywords = getKeywords(params); 106 if ("host" in keywords) { 107 host = keywords["host"]; 108 } 109 if ("dbname" in keywords) { 110 dbname = keywords["dbname"]; 111 } 112 if ("sock" in keywords) { 113 sock = keywords["sock"]; 114 } 115 if ("port" in keywords) { 116 port = cast(uint)tango.text.convert.Integer.parse(keywords["port"]); 117 } 118 } 119 if (tango.text.Util.contains(params, '=')) { 120 parseKeywords(); 121 } else { 122 dbname = params; 8 private import dbi.model.Database, 9 dbi.model.Result; 10 11 private import dbi.Exception; 12 13 private import dbi.mysql.MysqlError, 14 dbi.mysql.MysqlResult, 15 dbi.mysql.MysqlStatement; 16 17 private import dbi.mysql.c.mysql; 18 19 private import tango.util.log.Log, 20 tango.util.log.Config; 21 private import tango.core.Variant; 22 private import Integer = tango.text.convert.Integer; 23 private import tango.text.convert.Format; 24 25 private import tango.stdc.stringz; 26 27 class MysqlDatabase : Database 28 { 29 30 private: 31 32 Logger log; 33 34 package: 35 MYSQL* connection = null; 36 37 public: 38 39 this () 40 { 41 connection = mysql_init(null); 42 log = Log.lookup(this.classinfo.toString); 43 } 44 45 this (char[] name, char[] user = null, 46 char[] password = null, 47 char[][char[]] params = null) 48 { 49 this(); 50 connect(name, user, password, params); 51 } 52 53 void connect (char[] name, char[] user = null, 54 char[] password = null, 55 char[][char[]] params = null) 56 { 57 char[] host = "localhost"; 58 char[] dbname = "test"; 59 char[] sock = null; 60 uint port = 0; 61 62 if ( connection is null ) 63 throw new Exception ("This database connection has been closed."); 64 65 if ("host" in params) 66 host = params["host"]; 67 if ("dbname" in params) 68 dbname = params["dbname"]; 69 if ("sock" in params) 70 sock = params["sock"]; 71 if ("port" in params) 72 port = cast(uint)Integer.parse(params["port"]); 73 74 // TODO: check docs - check for null? 75 mysql_real_connect(connection, toStringz(host), toStringz(user), 76 toStringz(password), toStringz(name), port, 77 toStringz(sock), 0); 78 if (uint error = mysql_errno(connection)) { 79 throw new DBIException("Unable to connect to the MySQL database.", 80 error, specificToGeneral(error)); 123 81 } 124 125 mysql_real_connect(connection, toCString(host), toCString(username), toCString(password), toCString(dbname), port, toCString(sock), 0); 126 if (uint error = mysql_errno(connection)) { 127 Cout("connect(): "); 128 Cout(toDString(mysql_error(connection))); 129 Cout("\n").flush; 130 throw new DBIException("Unable to connect to the MySQL database.", error, specificToGeneral(error)); 131 } 132 } 133 134 /** 135 * Close the current connection to the database. 136 * 137 * Throws: 138 * DBIException if there was an error disconnecting. 139 */ 140 override void close () { 141 if (connection !is null) { 82 } 83 84 void close() 85 { 86 if (connection !is null) { 142 87 mysql_close(connection); 143 88 if (uint error = mysql_errno(connection)) { 144 Cout("close(): ");145 Cout(toDString(mysql_error(connection)));146 Cout("\n").flush;147 89 throw new DBIException("Unable to close the MySQL database.", error, specificToGeneral(error)); 148 90 } 149 91 connection = null; 150 92 } 151 } 152 153 /** 154 * Execute a SQL statement that returns no results. 155 * 156 * Params: 157 * sql = The SQL statement to _execute. 158 * 159 * Throws: 160 * DBIException if the SQL code couldn't be executed. 161 */ 162 override void execute (char[] sql) { 163 int error = mysql_real_query(connection, toCString(sql), sql.length); 93 } 94 95 void execute(char[] sql) 96 { 97 int error = mysql_real_query(connection, sql.ptr, sql.length); 164 98 if (error) { 165 Cout("execute(): "); 166 Cout(toDString(mysql_error(connection))); 167 Cout("\n").flush; 168 throw new DBIException("Unable to execute a command on the MySQL database.", sql, error, specificToGeneral(error)); 169 } 170 } 171 172 /** 173 * Query the database. 174 * 175 * Bugs: 176 * This does not currently check for errors. 177 * 178 * Params: 179 * sql = The SQL statement to execute. 180 * 181 * Returns: 182 * A Result object with the queried information. 183 */ 184 override MysqlResult query (char[] sql) { 185 mysql_real_query(connection, toCString(sql), sql.length); 186 MYSQL_RES* results = mysql_store_result(connection); 187 if (results is null) { 188 Cout("query(): "); 189 Cout(toDString(mysql_error(connection))); 190 Cout("\n").flush; 191 throw new DBIException("Unable to query the MySQL database.", sql); 192 } 193 assert (results !is null); 194 return new MysqlResult(results); 195 } 196 197 /** 198 * Get the error code. 199 * 200 * Deprecated: 201 * This functionality now exists in DBIException. This will be 202 * removed in version 0.3.0. 203 * 204 * Returns: 205 * The database specific error code. 206 */ 207 deprecated override int getErrorCode () { 208 Cout("GetErrorCode: "); 209 Cout(toDString(mysql_error(connection))); 210 Cout("\n").flush; 211 return cast(int)mysql_errno(connection); 212 } 213 214 /** 215 * Get the error message. 216 * 217 * Deprecated: 218 * This functionality now exists in DBIException. This will be 219 * removed in version 0.3.0. 220 * 221 * Returns: 222 * The database specific error message. 223 */ 224 deprecated override char[] getErrorMessage () { 225 return toDString(mysql_error(connection)); 226 } 227 228 /** 229 * Get the integer id of the last row to be inserted. 230 * 231 * Returns: 232 * The id of the last row inserted into the database. 233 */ 234 override long getLastInsertID() { 235 return mysql_insert_id(connection); 99 throw new DBIException("Unable to execute a command on the MySQL database.", sql, error, specificToGeneral(error)); 100 } 101 } 102 103 MysqlResult query(char[] sql) 104 { 105 execute(sql); 106 auto results = mysql_store_result(connection); 107 108 if (results is null) { 109 throw new DBIException("Unable to query the MySQL database using: " ~ sql); 236 110 } 237 238 static this() 239 { 240 mysqlSqlGen = new MysqlSqlGenerator; 241 } 242 private static MysqlSqlGenerator mysqlSqlGen; 243 244 override SqlGenerator getSqlGenerator() 245 { 246 return mysqlSqlGen; 247 } 248 249 package: 250 MYSQL* connection; 111 112 return new MysqlResult(results); 113 } 114 115 MysqlStatement prepare(char[] sql) 116 { 117 // TODO: prepared query syntax standardized? Will a dbms agnostic 118 // frontend need to adjust it? 119 auto stmt = mysql_stmt_init(connection); 120 auto results = mysql_stmt_prepare(stmt, sql.ptr, sql.length); 121 if(results != 0) { 122 auto err = mysql_stmt_error(stmt); 123 auto errno = mysql_stmt_errno(stmt); 124 throw new DBIException("Unable to prepare statement: " ~ sql, errno, 125 specificToGeneral(errno), fromStringz(err)); 126 } 127 return new MysqlStatement(stmt); 128 } 129 130 MysqlTables tables(char[] filter = null) 131 { 132 auto results = mysql_list_tables(connection, toStringz(filter)); 133 if(!results) { 134 log.error(fromStringz(mysql_error(connection))); 135 throw new DBIException("Table request returned null from MySQL"); 136 } 137 138 return new MysqlTables(this, new MysqlResult(results)); 139 } 140 141 bool hasTable(char[] name) 142 { 143 auto results = mysql_list_tables(connection, toStringz(name)); 144 if(!results) { 145 log.error(fromStringz(mysql_error(connection))); 146 throw new DBIException("Has Table request returned null from MySQL"); 147 } 148 bool exists = mysql_num_rows(results) > 0; 149 mysql_free_result(results); 150 return exists; 151 } 152 153 ulong lastInsertID() 154 { 155 return mysql_insert_id(connection); 156 } 157 158 void beginTransact() 159 { 160 const char[] sql = "START TRANSACTION;"; 161 mysql_real_query(connection, sql.ptr, sql.length); 162 } 163 164 void rollback() 165 { 166 mysql_rollback(connection); 167 } 168 169 void commit() 170 { 171 mysql_commit(connection); 172 } 251 173 } 252 174 253 class Mysql SqlGenerator : SqlGenerator175 class MysqlTables : Tables 254 176 { 255 override char getIdentifierQuoteCharacter() 256 { 257 return '`'; 258 } 177 private: 178 179 MysqlRows tablerows; 180 MysqlDatabase dbase; 181 182 public: 183 184 this (MysqlDatabase dbase, MysqlResult results) 185 { 186 this.tablerows = new MysqlRows(results); 187 this.dbase = dbase; 188 } 189 190 int opApply (int delegate(inout Table) dg) 191 { 192 if (!tablerows.valid) 193 throw new DBIException("The underlying result set is no longer valid"); 194 195 int result; 196 MysqlTable table = new MysqlTable(dbase); 197 foreach (Row tablerow; tablerows) { 198 table.set(tablerow.stringAt(0)); 199 Table t = table; 200 if ((result = dg(t)) != 0) 201 break; 202 } 203 return result; 204 } 205 206 size_t tables() { return tablerows.rowCount; } 259 207 } 260 208 261 private class MysqlRegister : Registerable { 262 263 public char[] getPrefix() { 264 return "mysql"; 265 } 266 267 public Database getInstance(char[] url) { 268 //parse the URL here 269 return new MysqlDatabase(); 270 } 209 class MysqlTable : Table 210 { 211 private: 212 213 char[] _name = null; 214 MysqlDatabase dbase; 215 ulong _rowCount; 216 ColumnInfo[] _metadata = null; 217 218 public: 219 220 this(MysqlDatabase dbase) 221 { 222 this.dbase = dbase; 223 } 224 225 this(MysqlDatabase dbase, char[] name) 226 { 227 this(dbase); 228 _name = name; 229 } 230 231 void set(char[] name) 232 in { 233 assert (name !is null); 234 } 235 body { 236 _name = name; 237 } 238 239 char[] name() { 240 return _name; 241 } 242 243 ColumnInfo[] metadata() 244 { 245 char[96] fieldquerybuf; 246 auto fieldquery = Format.sprint(fieldquerybuf, "SELECT * FROM {} LIMIT 1;", name); 247 fieldquerybuf[fieldquery.length] = 0; 248 249 mysql_real_query(dbase.connection, fieldquery.ptr, fieldquery.length); 250 auto results = mysql_store_result(dbase.connection); 251 auto fields = mysql_fetch_fields(results); 252 253 _metadata = new ColumnInfo[mysql_num_fields(results)]; 254 for (ulong i = 0; i < mysql_num_fields(results); i++) { 255 fromMysqlField(_metadata[i], fields[i]); 256 } 257 258 mysql_free_result(results); 259 260 return _metadata; 261 } 262 263 ColumnInfo metadata(size_t idx) 264 in { 265 if (_metadata !is null) 266 assert (idx > 0 && idx < _metadata.length); 267 } 268 body { 269 if (_metadata is null) 270 metadata(); 271 return _metadata[idx]; 272 } 273 274 ulong fieldCount() 275 { 276 if (_metadata is null) 277 metadata(); 278 return _metadata.length; 279 } 280 281 ulong rowCount() { 282 return _rowCount; 283 } 284 285 MysqlRows rows() 286 { 287 char[96] rowquerybuf; 288 auto rowquery = Format.sprint(rowquerybuf, "SELECT * FROM {};", name); 289 rowquerybuf[rowquery.length] = 0; 290 291 mysql_real_query(dbase.connection, rowquery.ptr, rowquery.length); 292 auto results = mysql_store_result(dbase.connection); 293 294 _rowCount = mysql_num_rows(results); 295 if (results is null) { 296 throw new DBIException("Unable to query the MySQL database for rows."); 297 } 298 299 return (new MysqlResult(results)).rows; 300 } 301 302 char[] toString() { return name; } 271 303 } 272 304 273 static this() {274 Cout("Attempting to register MysqlDatabase in Registry").newline;275 registerDatabase(new MysqlRegister());276 }277 278 debug(UnitTest) {279 unittest {280 281 void s1 (char[] s) {282 tango.io.Stdout.Stdout(s).newline();283 }284 285 void s2 (char[] s) {286 tango.io.Stdout.Stdout(" ..." ~ s).newline();287 }288 289 s1("dbi.mysql.MysqlDatabase:");290 MysqlDatabase db = new MysqlDatabase();291 /+ s2("connect");292 db.connect("dbname=test", "test", "test");293 294 s2("query");295 Result res = db.query("SELECT * FROM test");296 assert (res !is null);297 298 s2("fetchRow");299 Row row = res.fetchRow();300 assert (row !is null);301 assert (row.getFieldIndex("id") == 0);302 assert (row.getFieldIndex("name") == 1);303 assert (row.getFieldIndex("dateofbirth") == 2);304 assert (row.get("id") == "1");305 assert (row.get("name") == "John Doe");306 assert (row.get("dateofbirth") == "1970-01-01");307 /** Todo: MySQL type retrieval is not functioning */308 //assert (row.getFieldType(1) == FIELD_TYPE_STRING);309 //assert (row.getFieldDecl(1) == "char(40)");310 res.finish();311 312 s2("prepare");313 Statement stmt = db.prepare("SELECT * FROM test WHERE id = ?");314 stmt.bind(1, "1");315 res = stmt.query();316 row = res.fetchRow();317 res.finish();318 assert (row[0] == "1");319 320 s2("fetchOne");321 row = db.queryFetchOne("SELECT * FROM test");322 assert (row[0] == "1");323 324 s2("execute(INSERT)");325 db.execute("INSERT INTO test VALUES (2, 'Jane Doe', '2000-12-31')");326 327 s2("execute(DELETE via prepare statement)");328 stmt = db.prepare("DELETE FROM test WHERE id=?");329 stmt.bind(1, "2");330 stmt.execute();331 332 s2("close");333 db.close();+/334 auto sqlgen = db.getSqlGenerator;335 auto res = sqlgen.makeInsertSql("user", ["name", "date"]);336 assert(res == "INSERT INTO `user` (`name`,`date`) VALUES(?,?)", res);337 }338 }339 340 }trunk/dbi/mysql/MysqlError.d
r70 r95 8 8 9 9 private import dbi.ErrorCode; 10 11 package: 10 12 11 13 /** … … 21 23 * Written against the MySQL 5.1 documentation (revision 2737) 22 24 */ 23 package ErrorCode specificToGeneral (uint error) { 25 26 ErrorCode specificToGeneral (uint error) { 24 27 if (error > 999 && error < 2000) { 25 28 return ErrorCode.ServerError; … … 141 144 return ErrorCode.Unknown; 142 145 } 143 // Bugfix for DMD 0.162144 return ErrorCode.Unknown;146 // Return workaround 147 return ErrorCode.Unknown; 145 148 } 146 149 trunk/dbi/mysql/MysqlResult.d
r89 r95 3 3 * Copyright: BSD license 4 4 */ 5 5 6 module dbi.mysql.MysqlResult; 6 7 7 version (dbi_mysql) { 8 private import tango.stdc.stringz : asString = fromStringz; 9 private import dbi.DBIException, dbi.Result, dbi.Row; 10 version(Windows) { 11 private import dbi.mysql.imp_win; 12 } 13 else { 14 private import dbi.mysql.imp; 15 } 16 17 /** 18 * Manage a result set from a MySQL database query. 19 * 20 * See_Also: 21 * Result is the interface of which this provides an implementation. 22 */ 23 class MysqlResult : Result { 24 public: 25 this (MYSQL_RES* results) { 26 this.results = results; 27 28 fields = mysql_fetch_fields(results); 29 fieldCount = mysql_num_fields(results); 30 } 31 32 /** 33 * Get the next row from a result set. 34 * 35 * Returns: 36 * A Row object with the queried information or null for an empty set. 37 */ 38 override Row fetchRow () { 39 MYSQL_ROW row = mysql_fetch_row(results); 40 uint* lengths = mysql_fetch_lengths(results); 41 if (row is null) { 42 return null; 43 } 44 assert (lengths !is null); 45 Row r = new Row(); 46 for (uint index = 0; index < fieldCount; index++) { 47 r.addField(asString(fields[index].name), row[index][0 .. lengths[index]], "", fields[index].type); 48 } 49 return r; 50 } 51 52 /** 53 * Free all database resources used by a result set. 54 */ 55 override void finish () { 56 if (results !is null) { 57 mysql_free_result(results); 58 results = null; 59 } 60 } 61 62 private: 63 MYSQL_RES* results; 64 const MYSQL_FIELD* fields; 65 const uint fieldCount; 66 } 67 68 } 8 private import dbi.model.Result, 9 dbi.model.Types; 10 11 private import dbi.mysql.c.mysql; 12 13 private import dbi.mysql.MysqlDatabase; 14 15 private import tango.core.Variant; 16 private import tango.util.log.Log; 17 18 debug private import tango.io.Stdout; 19 20 class MysqlResult : FullResult 21 { 22 private: 23 MysqlRows _rows; 24 Alloc _alloc; 25 ColumnInfo[] _metadata; 26 27 package: 28 MYSQL_RES* result = null; 29 30 public: 31 this(MYSQL_RES* res) 32 in { 33 assert (res !is null); 34 } 35 body { 36 result = res; 37 _rows = null; 38 } 39 40 void set(MYSQL_RES* res) 41 { 42 if (result !is null) 43 close; 44 45 result = res; 46 } 47 48 MysqlRows rows() 49 { 50 if (_rows is null) 51 _rows = new MysqlRows(this); 52 53 return _rows; 54 } 55 56 ColumnInfo[] metadata() 57 { 58 auto fields = mysql_fetch_fields(result); 59 60 _metadata = new ColumnInfo[fieldCount]; 61 for (ulong i = 0; i < fieldCount; i++) { 62 fromMysqlField(_metadata[i], fields[i]); 63 } 64 65 return _metadata; 66 } 67 68 ColumnInfo metadata(size_t idx) 69 in { 70 if (_metadata !is null) 71 assert (idx > 0 && idx < _metadata.length); 72 } 73 body { 74 if (_metadata is null) 75 metadata(); 76 return _metadata[idx]; 77 } 78 79 ulong rowCount() { return mysql_num_rows(result); } 80 ulong fieldCount() { return mysql_num_fields(result); } 81 82 Alloc allocator() 83 { 84 return _alloc; 85 } 86 87 void allocator(Alloc alloc) 88 { 89 _alloc = alloc; 90 } 91 92 void close() 93 { 94 if (result is null) 95 throw new Exception ("This result set was already closed."); 96 97 mysql_free_result(result); 98 result = null; 99 } 100 101 bool valid() { return result !is null; } 102 } 103 104 class MysqlRows : Rows 105 { 106 private: 107 108 MysqlResult _rows; 109 ColumnInfo[] _metadata; 110 Alloc _alloc; 111 112 Logger log; 113 114 public: 115 116 this (MysqlResult results) 117 { 118 _rows = results; 119 log = Log.lookup(this.classinfo.name); 120 } 121 122 ulong rowCount() 123 { 124 return _rows.rowCount; 125 } 126 127 ulong fieldCount() 128 { 129 return _rows.fieldCount; 130 } 131 132 ColumnInfo[] metadata() 133 { 134 auto fields = mysql_fetch_fields(_rows.result); 135 136 _metadata = new ColumnInfo[_rows.fieldCount]; 137 for (ulong i = 0; i < _rows.fieldCount; i++) { 138 fromMysqlField(_metadata[i], fields[i]); 139 } 140 141 return _metadata; 142 } 143 144 ColumnInfo metadata(size_t idx) 145 in { 146 if (_metadata !is null) 147 assert (idx > 0 && idx < _metadata.length); 148 } 149 body { 150 if (_metadata is null) 151 metadata(); 152 return _metadata[idx]; 153 } 154 155 int opApply (int delegate(inout Row) dg) 156 { 157 int result; 158 MysqlRow host = new MysqlRow; 159 MYSQL_ROW row; 160 assert (_rows.valid); 161 while ((row = mysql_fetch_row(_rows.result)) !is null) { 162 host.set(row, mysql_fetch_lengths(_rows.result)); 163 Row r = host; 164 if ((result = dg(r)) != 0) 165 break; 166 } 167 return result; 168 } 169 170 Alloc allocator() 171 { 172 return _alloc; 173 } 174 175 void allocator(Alloc alloc) 176 { 177 _alloc = alloc; 178 } 179 180 Row next() 181 { 182 return new MysqlRow(_rows); 183 } 184 185 bool fetch(Alloc alloc, void* ...) 186 { 187 // TODO 188 return false; 189 } 190 191 Row opIndex(ulong idx) 192 { 193 // TODO 194 return null; 195 } 196 197 void seek(ulong offset) 198 { 199 mysql_data_seek(_rows.result, offset); 200 } 201 202 bool valid() { return _rows.valid; } 203 204 } 205 206 class MysqlRow : Row 207 { 208 private: 209 MysqlResult _results = null; 210 MYSQL_ROW _row; 211 uint* _lengths = null; 212 private Logger log; 213 214 private: 215 216 void initRow() { 217 _row = mysql_fetch_row(_results.result); 218 _lengths = mysql_fetch_lengths(_results.result); 219 } 220 221 222 public: 223 224 this () 225 { 226 log = Log.getLogger(this.classinfo.toString); 227 } 228 229 this (MysqlResult results) 230 in { 231 assert (results !is null); 232 } 233 body { 234 _results = results; 235 initRow; 236 } 237 238 this (MYSQL_ROW row, uint* lengths) 239 { 240 _row = row; 241 _lengths = lengths; 242 } 243 244 245 MysqlRow set(MYSQL_ROW row, uint* lengths) 246 { 247 _row = row; 248 _lengths = lengths; 249 return this; 250 } 251 252 MysqlRow set(MysqlResult results) { 253 _results = results; 254 initRow; 255 256 return this; 257 } 258 259 ColumnInfo[] metadata() 260 { 261 return _results.metadata(); 262 } 263 264 ColumnInfo metadata(size_t idx) 265 { 266 return _results.metadata(idx); 267 } 268 269 ulong fieldCount() 270 { 271 return _results.fieldCount; 272 } 273 274 char[] stringAt(size_t idx) 275 { 276 return _row[idx][0 .. _lengths[idx]]; 277 } 278 279 char[] stringAt(char[] name) 280 { 281 foreach (i, column; metadata) 282 if (name is column.name) 283 return _row[i][0 .. _lengths[i]]; 284 285 return null; 286 } 287 288 void fetch(inout char[][] values) 289 in { 290 assert (values.length >= fieldCount); 291 } 292 body { 293 for (int i = 0; i < fieldCount; i++) { 294 values[i] = _row[i][0 .. _lengths[i]]; 295 } 296 } 297 298 void fetch(inout char[] value, size_t idx = 0) 299 in { 300 assert(idx < fieldCount); 301 } 302 body { 303 value = _row[idx][0 .. _lengths[idx]]; 304 } 305 } 306 307 package: 308 309 DbiType fromMysqlType(enum_field_types type) 310 { 311 with (enum_field_types) { 312 switch (type) { 313 case MYSQL_TYPE_DECIMAL: 314 return DbiType.Decimal; 315 case MYSQL_TYPE_TINY: 316 return DbiType.Byte; 317 case MYSQL_TYPE_SHORT: 318 return DbiType.Short; 319 case MYSQL_TYPE_LONG: 320 case MYSQL_TYPE_ENUM: 321 return DbiType.Int; 322 case MYSQL_TYPE_FLOAT: 323 return DbiType.Float; 324 case MYSQL_TYPE_DOUBLE: 325 return DbiType.Double; 326 case MYSQL_TYPE_NULL: 327 return DbiType.Null; 328 case MYSQL_TYPE_TIMESTAMP: 329 return DbiType.DateTime; 330 case MYSQL_TYPE_LONGLONG: 331 return DbiType.Long; 332 case MYSQL_TYPE_INT24: 333 return DbiType.Int; 334 case MYSQL_TYPE_DATE: 335 case MYSQL_TYPE_TIME: 336 case MYSQL_TYPE_DATETIME: 337 case MYSQL_TYPE_YEAR: 338 case MYSQL_TYPE_NEWDATE: 339 return DbiType.DateTime; 340 case MYSQL_TYPE_BIT: 341 assert(false); 342 case MYSQL_TYPE_NEWDECIMAL: 343 return DbiType.Decimal; 344 case MYSQL_TYPE_SET: 345 assert(false); 346 case MYSQL_TYPE_TINY_BLOB: 347 case MYSQL_TYPE_MEDIUM_BLOB: 348 case MYSQL_TYPE_LONG_BLOB: 349 case MYSQL_TYPE_BLOB: 350 return DbiType.Binary; 351 case MYSQL_TYPE_VARCHAR: 352 case MYSQL_TYPE_VAR_STRING: 353 case MYSQL_TYPE_STRING: 354 return DbiType.String; 355 case MYSQL_TYPE_GEOMETRY: 356 assert(false); 357 default: 358 return DbiType.None; 359 } 360 } 361 } 362 363 void fromMysqlField(inout ColumnInfo column, MYSQL_FIELD field) 364 { 365 column.name = field.name[0..field.name_length]; 366 column.name.length = field.name_length; 367 column.type = fromMysqlType(field.type); 368 column.flags = field.flags; 369 } trunk/dbi/mysql/c/mysql.d
- Property svn:mergeinfo set
r81 r95 1 /**1 /** 2 2 * Authors: The D DBI project 3 3 * Copyright: BSD license 4 4 */ 5 module dbi.mysql. imp;5 module dbi.mysql.c.mysql; 6 6 7 7 version (dbi_mysql) { 8 8 9 extern ( C):9 extern (System): 10 10 11 11 version (Windows) { 12 12 pragma (lib, "libmysql.lib"); 13 } else version (linux) { 14 pragma (lib, "libmysql.a"); 15 } else version (Posix) { 16 pragma (lib, "libmysql.a"); 17 } else version (darwin) { 18 pragma (lib, "libmysql.a"); 19 } else { 20 pragma (msg, "You will need to manually link in the MySQL library."); 21 } 13 } 22 14 23 15 version(MySQL_51) { trunk/dsss.conf
r87 r95 1 1 name=dbi 2 exclude=buildme.d3 2 4 3 [testddbi.d] … … 6 5 7 6 [dbi] 7 version (dbi_mysql) { 8 buildflags += -L-lmysqlclient 9 } 8 10 target=dbi 9 11
