1 module mysql.mysql_result; 2 3 import std.stdio; 4 import std.exception; 5 6 import mysql.binding; 7 import mysql.mysql_row; 8 9 class MysqlResult { 10 private int[string] mapping; 11 public MYSQL_RES* result; 12 13 private int itemsTotal; 14 private int itemsUsed; 15 16 bool[] columnIsNull; 17 MysqlRow row; 18 19 string sql; 20 21 this(MYSQL_RES* r, string sql) { 22 result = r; 23 itemsTotal = length(); 24 itemsUsed = 0; 25 26 this.sql = sql; 27 28 // prime it 29 if (itemsTotal) { 30 fetchNext(); 31 } 32 } 33 34 ~this() { 35 if (result !is null) { 36 mysql_free_result(result); 37 } 38 } 39 40 41 MYSQL_FIELD[] fields() { 42 int numFields = mysql_num_fields(result); 43 auto fields = mysql_fetch_fields(result); 44 MYSQL_FIELD[] ret; 45 for(int i = 0; i < numFields; i++) { 46 ret ~= fields[i]; 47 } 48 49 return ret; 50 } 51 52 53 int length() { 54 if (result is null) { 55 return 0; 56 } 57 return cast(int) mysql_num_rows(result); 58 } 59 60 bool empty() { 61 return itemsUsed == itemsTotal; 62 } 63 64 MysqlRow front() { 65 return row; 66 } 67 68 void popFront() { 69 itemsUsed++; 70 if (itemsUsed < itemsTotal) { 71 fetchNext(); 72 } 73 } 74 75 int getFieldIndex(string field) { 76 if (mapping is null) { 77 makeFieldMapping(); 78 } debug { 79 if (field !in mapping) { 80 throw new Exception(field ~ " not in result"); 81 } 82 } 83 return mapping[field]; 84 } 85 86 string[] fieldNames() { 87 int numFields = mysql_num_fields(result); 88 auto fields = mysql_fetch_fields(result); 89 90 string[] names; 91 for(int i = 0; i < numFields; i++) { 92 names ~= fromCstring(fields[i].name, fields[i].name_length); 93 } 94 95 return names; 96 } 97 98 private void makeFieldMapping() { 99 int numFields = mysql_num_fields(result); 100 auto fields = mysql_fetch_fields(result); 101 102 if (fields is null) { 103 return; 104 } 105 106 for(int i = 0; i < numFields; i++) { 107 if (fields[i].name !is null) { 108 mapping[fromCstring(fields[i].name, fields[i].name_length)] = i; 109 } 110 } 111 } 112 113 private void fetchNext() { 114 assert(result); 115 auto my_row = mysql_fetch_row(result); 116 if (my_row is null) { 117 throw new Exception("there is no next row"); 118 } 119 uint numFields = mysql_num_fields(result); 120 uint* lengths = mysql_fetch_lengths(result); 121 string[] row; 122 // potential FIXME: not really binary safe 123 124 columnIsNull.length = numFields; 125 for(uint numField = 0; numField < numFields; numField++) { 126 //writefln("numField %d", numField); 127 if (my_row[numField] is null) { 128 row ~= null; 129 columnIsNull[numField] = true; 130 } else { 131 row ~= cast(string) cstr2dstr(my_row[numField], lengths[numField]); 132 columnIsNull[numField] = false; 133 } 134 } 135 136 this.row.row = row; 137 this.row.resultSet = this; 138 } 139 }