1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
#include "stdafx.h"
#include "Row.h"
#include "Exception.h"
namespace sql {
const GcType Row::elemType = {
GcType::tArray,
null,
null,
sizeof(Row::Element),
1,
{ OFFSET_OF(Row::Element, object) },
};
Row::Row() : data(null) {}
Row::Row(Builder b) : data(b.data) {
assert(data->filled == data->count, L"Data array was not properly filled before creating a row!");
}
void Row::deepCopy(CloneEnv *env) {
GcArray<Element> *copy = runtime::allocArray<Element>(env->engine(), &elemType, data->count);
memcpy(©->v[0], &data->v[0], sizeof(Element) * data->count);
data = copy;
}
const Row::Element &Row::checkIndex(Nat index) const {
if (!data || index >= data->count)
throw new (runtime::someEngine()) ArrayError(index, data ? Nat(data->count) : 0);
return data->v[index];
}
void Row::throwTypeError(const wchar *expected, const Element &found) const {
Engine &e = runtime::someEngine();
StrBuf *msg = new (e) StrBuf();
*msg << S("Expected type of column: ") << expected
<< S(", but column has type: ");
switch (size_t(found.object)) {
case COL_NULL:
*msg << S("NULL");
break;
case COL_LONG:
*msg << S("Long");
break;
case COL_DOUBLE:
*msg << S("Double");
break;
default:
if (size_t(found.object) < COL_LAST) {
*msg << S("<unknown>");
} else {
*msg << runtime::typeName(runtime::typeOf((RootObject *)found.object));
}
break;
}
throw new (e) SQLError(msg->toS());
}
Str *Row::getStr(Nat index) const {
const Element &e = checkIndex(index);
if (size_t(e.object) < COL_LAST)
throwTypeError(S("Str"), e);
Object *o = (Object *)e.object;
if (Str *s = as<Str>(o))
return s;
throwTypeError(S("Str"), e);
return null;
}
Bool Row::getBool(Nat index) const {
return getLong(index) != 0;
}
Int Row::getInt(Nat index) const {
return Int(getLong(index));
}
Long Row::getLong(Nat index) const {
const Element &e = checkIndex(index);
if (size_t(e.object) != COL_LONG)
throwTypeError(S("Long"), e);
return e.l;
}
Float Row::getFloat(Nat index) const {
return Float(getDouble(index));
}
Double Row::getDouble(Nat index) const {
const Element &e = checkIndex(index);
if (size_t(e.object) != COL_DOUBLE)
throwTypeError(S("Double"), e);
return e.d;
}
Bool Row::isNull(Nat index) const {
const Element &e = checkIndex(index);
return e.object == null;
}
Variant at(EnginePtr engine, const Row &row, Nat index) {
const Row::Element &e = row.checkIndex(index);
switch (size_t(e.object)) {
case Row::COL_NULL:
return Variant();
case Row::COL_LONG:
return Variant(e.l, engine.v);
case Row::COL_DOUBLE:
return Variant(e.d, engine.v);
default:
return Variant((RootObject *)e.object);
}
}
Row::Builder::Builder(GcArray<Element> *elems) : data(elems) {
elems->filled = 0;
}
Row::Builder Row::builder(EnginePtr e, Nat columns) {
return Builder(runtime::allocArray<Row::Element>(e.v, &elemType, columns));
}
Row::Element &Row::Builder::next() {
if (data->filled >= data->count)
throw new (runtime::someEngine()) ArrayError(Nat(data->filled), Nat(data->count));
return data->v[data->filled++];
}
void Row::Builder::push(Str *v) {
Element &e = next();
e.object = v;
}
void Row::Builder::push(Long l) {
Element &e = next();
e.object = (void *)COL_LONG;
e.l = l;
}
void Row::Builder::push(Double d) {
Element &e = next();
e.object = (void *)COL_DOUBLE;
e.d = d;
}
void Row::Builder::pushNull() {
Element &e = next();
e.object = null;
}
void Row::toS(StrBuf *to) const {
*to << S("row: ");
for (Nat i = 0; i < count(); i++) {
if (i > 0)
*to << S(", ");
// Note: slower than necessary, but OK for debugging.
*to << at(to->engine(), *this, i);
}
}
}
|