in hphp/runtime/ext/pdo/ext_pdo.cpp [1710:1999]
static bool do_fetch(sp_PDOStatement stmt,
Variant& ret,
PDOFetchType how,
PDOFetchOrientation ori,
long offset,
Variant *return_all) {
if (how == PDO_FETCH_USE_DEFAULT) {
how = stmt->default_fetch_type;
}
int flags = how & PDO_FETCH_FLAGS;
how = (PDOFetchType)(how & ~PDO_FETCH_FLAGS);
if (!do_fetch_common(stmt, ori, offset)) {
return false;
}
if (how == PDO_FETCH_BOUND) {
ret = true;
return true;
}
int colno;
if ((flags & PDO_FETCH_GROUP) && stmt->fetch.column == -1) {
colno = 1;
} else {
colno = stmt->fetch.column;
}
if (how == PDO_FETCH_LAZY) {
get_lazy_object(stmt, ret);
return true;
}
String clsname, old_clsname;
Variant old_ctor_args;
ret = false;
int i = 0;
switch (how) {
case PDO_FETCH_USE_DEFAULT:
case PDO_FETCH_ASSOC:
case PDO_FETCH_BOTH:
case PDO_FETCH_NUM:
case PDO_FETCH_NAMED:
ret = Array::CreateDict();
break;
case PDO_FETCH_KEY_PAIR:
if (stmt->column_count != 2) {
pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
"PDO::FETCH_KEY_PAIR fetch mode requires the "
"result set to contain extactly 2 columns.");
return false;
}
if (!return_all) {
ret = Array::CreateDict();
}
break;
case PDO_FETCH_COLUMN:
if (colno >= 0 && colno < stmt->column_count) {
if (flags == PDO_FETCH_GROUP && stmt->fetch.column == -1) {
fetch_value(stmt, ret, 1, NULL);
} else if (flags == PDO_FETCH_GROUP && colno) {
fetch_value(stmt, ret, 0, NULL);
} else {
fetch_value(stmt, ret, colno, NULL);
}
if (!return_all) {
return true;
}
break;
} else {
pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid column index");
}
return false;
case PDO_FETCH_OBJ:
ret = SystemLib::AllocStdClassObject();
break;
case PDO_FETCH_CLASS:
if (flags & PDO_FETCH_CLASSTYPE) {
old_clsname = stmt->fetch.clsname;
old_ctor_args = stmt->fetch.ctor_args;
Variant val;
fetch_value(stmt, val, i++, NULL);
if (!val.isNull()) {
if (!HHVM_FN(class_exists)(val.toString())) {
stmt->fetch.clsname = "stdclass";
} else {
stmt->fetch.clsname = val.toString();
}
}
do_fetch_class_prepare(stmt);
}
clsname = stmt->fetch.clsname;
if (clsname.empty()) {
pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
"No fetch class specified");
return false;
}
if ((flags & PDO_FETCH_SERIALIZE) == 0) {
ret = create_object_only(clsname);
if (!do_fetch_class_prepare(stmt)) {
return false;
}
if (!stmt->fetch.constructor.empty() &&
(flags & PDO_FETCH_PROPS_LATE)) {
ret.asCObjRef()->o_invoke(stmt->fetch.constructor,
stmt->fetch.ctor_args.toArray());
}
}
break;
case PDO_FETCH_INTO:
if (stmt->fetch.into.isNull()) {
pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
"No fetch-into object specified.");
return false;
}
ret = stmt->fetch.into;
if (ret.isObject() &&
ret.getObjectData()->instanceof(SystemLib::s_stdclassClass)) {
how = PDO_FETCH_OBJ;
}
break;
case PDO_FETCH_FUNC:
if (stmt->fetch.func.empty()) {
pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
"No fetch function specified");
return false;
}
if (!do_fetch_func_prepare(stmt)) {
return false;
}
break;
default:
assertx(false);
return false;
}
Variant grp_val;
if (return_all && how != PDO_FETCH_KEY_PAIR) {
if (flags == PDO_FETCH_GROUP && how == PDO_FETCH_COLUMN &&
stmt->fetch.column > 0) {
fetch_value(stmt, grp_val, colno, NULL);
} else {
fetch_value(stmt, grp_val, i, NULL);
}
grp_val = grp_val.toString();
if (how == PDO_FETCH_COLUMN) {
i = stmt->column_count; /* no more data to fetch */
} else {
i++;
}
}
for (int idx = 0; i < stmt->column_count; i++, idx++) {
const String& name = cast<PDOColumn>(stmt->columns[i])->name;
Variant val;
fetch_value(stmt, val, i, NULL);
switch (how) {
case PDO_FETCH_ASSOC: {
auto const name_key =
ret.asArrRef().convertKey<IntishCast::Cast>(name);
ret.asArrRef().set(name_key, *val.asTypedValue());
break;
}
case PDO_FETCH_KEY_PAIR: {
Variant tmp;
fetch_value(stmt, tmp, ++i, NULL);
if (return_all) {
auto const val_key_ret =
return_all->asArrRef().convertKey<IntishCast::Cast>(val);
return_all->asArrRef().set(val_key_ret, *tmp.asTypedValue());
} else {
auto const val_key =
ret.asArrRef().convertKey<IntishCast::Cast>(val);
ret.asArrRef().set(val_key, *tmp.asTypedValue());
}
return true;
}
case PDO_FETCH_USE_DEFAULT:
case PDO_FETCH_BOTH: {
auto const name_key =
ret.asArrRef().convertKey<IntishCast::Cast>(name);
ret.asArrRef().set(name_key, *val.asTypedValue());
ret.asArrRef().append(val);
break;
}
case PDO_FETCH_NAMED: {
auto const name_key =
ret.asArrRef().convertKey<IntishCast::Cast>(name);
/* already have an item with this name? */
forceToDict(ret);
if (ret.asArrRef().exists(name_key)) {
auto const curr_val = ret.asArrRef().lval(name_key);
if (!isArrayLikeType(curr_val.type())) {
Array arr = Array::CreateVec();
arr.append(curr_val.tv());
arr.append(val);
ret.toArray().set(name_key, make_array_like_tv(arr.get()));
} else {
asArrRef(curr_val).append(val);
}
} else {
ret.asArrRef().set(name_key, *val.asTypedValue());
}
break;
}
case PDO_FETCH_NUM:
ret.asArrRef().append(val);
break;
case PDO_FETCH_OBJ:
case PDO_FETCH_INTO:
ret.toObject()->o_set(name, val);
break;
case PDO_FETCH_CLASS:
if ((flags & PDO_FETCH_SERIALIZE) == 0 || idx) {
ret.toObject()->o_set(name, val);
} else {
#ifdef MBO_0
ret = unserialize_from_string(val);
if (same(ret, false)) {
pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
"cannot unserialize data");
return false;
}
#endif
// hzhao: not sure how we support class serialization
pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
"cannot unserialize class");
return false;
}
break;
case PDO_FETCH_FUNC:
forceToDict(stmt->fetch.values).set(idx, val);
break;
default:
pdo_raise_impl_error(stmt->dbh, stmt, "22003", "mode is out of range");
return false;
}
}
switch (how) {
case PDO_FETCH_CLASS:
if (!stmt->fetch.constructor.empty() &&
!(flags & (PDO_FETCH_PROPS_LATE | PDO_FETCH_SERIALIZE))) {
ret.toObject()->o_invoke(stmt->fetch.constructor,
stmt->fetch.ctor_args.toArray());
}
if (flags & PDO_FETCH_CLASSTYPE) {
stmt->fetch.clsname = old_clsname;
stmt->fetch.ctor_args = old_ctor_args;
}
break;
case PDO_FETCH_FUNC:
ret = vm_call_user_func(stmt->fetch.func,
stmt->fetch.values.toArray());
break;
default:
break;
}
if (return_all) {
auto const grp_key =
return_all->asArrRef().convertKey<IntishCast::Cast>(grp_val);
if ((flags & PDO_FETCH_UNIQUE) == PDO_FETCH_UNIQUE) {
return_all->asArrRef().set(grp_key, *ret.asTypedValue());
} else {
auto const lval = return_all->asArrRef().lval(grp_key);
forceToArray(lval).append(ret);
}
}
return true;
}