У вас есть это:
$stmtupdate = $conn->prepare("UPDATE $table SET ? = ? WHERE email = ?");
$stmtupdate->bind_param("sis", $column, $value, $email);
Это приводит к этому SQL:
UPDATE $table
SET @var1 = @var2 WHERE email = @var3
заменен, например, на
UPDATE $table
SET 'column' = 123 WHERE email = 'something'
Но вы хотите что-то вроде [ 118]
UPDATE mytable
SET mycolumn = 123 WHERE email = 'something'
Итак, есть две ошибки: вам нужно имя таблицы, а не $ table. И вам нужно имя столбца, а не значение переменной связывания строк.
Использовать конкатенацию строк:
$stmtupdate = $conn->prepare("UPDATE ".$table." SET ".$column." = ? WHERE email = ?");
$stmtupdate->bind_param("is", $value, $email);
(надеюсь, я не ошибаюсь. Прошло некоторое время с тех пор, как я использовал PHP с SQL.)
Field
один не тип, а шаблон, который может генерировать семейство типов, такой как Field<int>
и Field<double>
. Все эти поля не связаны таким образом, что тот так или иначе получен из другой или такой. Таким образом, необходимо установить некоторое отношение между всеми этими сгенерированными типами. Один путь состоит в том, чтобы использовать общий нешаблонный базовый класс:
class FieldBase { };
template <typename T>
class Field : public FieldBase {
private:
T value;
DataType<T> type;
};
class Row {
private:
std::map<unsigned long,FieldBase*> column;
};
И рассмотрите использование интеллектуального указателя вместо того необработанного указателя в коде. Так или иначе теперь проблема состоит в том, что информация типа потеряна - указываете ли Вы на a Field<double>
или к a Field<int>
больше не известен и может только быть обнаружен путем хранения своего рода флага типа в основе, которая установлена шаблонным производным классом - или путем выяснения у использования RTTI
dynamic_cast<Field<int>*>(field) != 0
Но это ужасно. Особенно, потому что, что Вы хотите, существует семантическое значение. Т.е. Вы хотели бы смочь скопировать свою строку, и она скопирует все поля в нем. И Вы хотели бы получить двойное, когда двойное хранится - без первого использования RTTI для взламывания пути к производному типу.
Один способ сделать его состоит в том, чтобы использовать дизъюнктное объединение. Это - в основном объединение для некоторых произвольных типов и кроме того флага типа, который хранит, какое значение в настоящее время хранится в том поле (например, ли двойное, международное...). Например:
template <typename T>
class Field {
private:
T value;
DataType<T> type;
};
class Row {
private:
std::map<unsigned long,
boost::variant< Field<int>, Field<double> > >
column;
};
повышение:: вариант делает всю работу для Вас. Можно использовать посещение, чтобы заставить его назвать функтор с помощью правильной перегрузки. Взгляните на его руководство
Теперь, для ответа на вопрос :), Поле <> классы могут наследоваться общему базовому классу, это совместно используется всеми типами данных. Таким образом, контейнер, такой как Ваша карта столбца может сохранить указатели (сделайте, это совместно использовало указатели) к производным объектам, которые инстанцируются шаблонного класса.
A Row< int, float, int>
действительно отличается от a Row<int, std::string>
. Очевидно, Row<int,float,int>.field<0>
должен быть a Field<int>
в то время как Row<int,float,int>.field<1>
должен быть a Field<float>
. И Row<int,float,int>.field<3>
ошибка компилятора.
Самый легкий способ сделать так использует Повышение. Большая аналитика была введена впервые Loki (см. современный Дизайн C++ Andrei Alexandrescu), но Повышение более современно и лучше поддерживаемый.
Обычно, Вы не выполнили бы итерации по полям - каждое поле имеет свой собственный тип. Но Вас делают, Вам действительно был бы нужен a FieldBase
. При необходимости в таком интерфейсе, вероятно, стоит также сохранить поля внутренне как a boost::array<FieldBase, N>
(т.е. Row<int,float,int>
имеет a boost::array<FieldBase, 3>
). Вы никогда не должны должны быть dynamic_cast
это FieldBase*
,все же. Это - тест во время выполнения, и Вы всегда знаете точное T
из каждого Field<T>
во время компиляции.