| пт 13 Май 2011 | | Разместил(а): ib | | Просмотров: менее 10 |
Мне нравится, когда в одной строчке кода выполняется сразу несколько операций, это удобно и наглядно. Ярким примером такого подхода является использование Javascript-библиотеки jQuery, которая применяется для разработки веб-приложений и "оживления" веб-сайтов. В статье сравниваются подходы написания функций с переменным количеством параметров в Delphi и Qt (язык C).
Для работы с базами данных я всегда пишу собственный класс, который позволяет выполнять запросы на выборку, изменение, удаление и добавление записей в одну строчку. Его-то мы и рассмотрим в качестве примера. Здесь необходимо передавать переменное количество аргументов в execute() - функцию выполнения SQL-запроса. Причём первый аргумент - это всегда текст SQL-запроса, в котором подставляемые значения указываются через знак вопроса "?", следующие не обязательные - значения этих подставляемых параметров (тип данных может быть разным - например, строки, целые и вещественные числа). Бывают случаи, когда функция может вообще не принимать ни одного аргумента. Но в Qt (Си), увы, необходимо всегда знать количество обрабатываемых аргументов и их тип данных, т.е. должен быть один обязательный параметр, в котором сообщается в том или ином виде сколько надо считать аргументов и какого они типа данных. В Delphi всё проще и удобнее - в теле функции доступен массив, количество элементов которого определяется стандартной функцией High(), а тип - свойством каждого элемента массива vtype. Объявление функции выглядит так: function TSQL.execute(pvals: array of const): Boolean;
Пример на Qt - описание класса TSQL и код функции execute():
// Класс для работы с БД с возможностью выполнить типовой запрос в 1 строку +фишки
class TSQL : public QObject {
Q_OBJECT
private:
QSqlQuery * qr;
public:
explicit TSQL(QObject *parent = 0);
void init();
bool execute(char * sql, char * ftypes, ...);
int quanRows();
int getNewID(QString gname);
bool fetch_row(QStringList*);
};
bool TSQL::execute(char * sql, char * ftypes,...) {
qr->prepare(sql);
va_list argptr; // Объявляем переменную, в которой будет указатель на текущий аргумент
va_start(argptr, ftypes); // Вот здесь-то и проблема №1 - указатель задаётся всегда // относительно какого-нибудь обязательного аргумента :(( int i = -1;
while( *ftypes != '\0' ) {
i++; // va_arg - считать следующий аргумент. Здесь проблема №2 - нужно всегда знать тип // Тип мы определяем из второй переменной ftypes if (*ftypes == 'f' ) qr->bindValue(i, va_arg( argptr, double )); // float
else if (*ftypes == 's' ) qr->bindValue(i, va_arg( argptr, char * )); // string
else qr->bindValue(i, va_arg( argptr, int )); // integer
ftypes++;
} va_end( argptr);
qr->exec();
return true;
}
Вызов функции будет выглядеть, например, так:
qr.execute("select id, pw from ldr_performer where (lower(code) = lower(?))", "s", dbLogin.data().toLocal8Bit());
// "s" - тип данных первого не обязательного аргумента (строка)
Пример на Delphi - код функции execute():
function TSQL.execute(pvals: array of const): Boolean;
var
var
i: Integer;
_sql: String;
begin
_sql := '';
if (High(pvals) > -1) then _sql := String(pvals[0].VString);
prepare(_sql);
for i := 1 to High(pvals) do
replace(@sqltext, '?', ':param'+its(i), true);
setSQL(sqltext);
for i := 1 to High(pvals) do begin
case (pvals[i].VType) of
vtInteger: setParam('param'+its(i), pvals[i].VInteger);
vtString: setParam('param'+its(i), String(pvals[i].VString));
vtExtended: setParam('param'+its(i), pvals[i].VExtended^);
vtVariant: setParam('param'+its(i), pvals[i].VVariant^);
else setParam('param'+its(i), String(pvals[i].VString));
end;
end;
if (isSel) then qr.Open else begin
qr.ExecSQL;
qr.Close;
end;
isPrepare := false;
result := true;
if (IP='') then getIP;
end;
_sql: String;
begin
_sql := '';
if (High(pvals) > -1) then _sql := String(pvals[0].VString);
prepare(_sql);
for i := 1 to High(pvals) do
replace(@sqltext, '?', ':param'+its(i), true);
setSQL(sqltext);
for i := 1 to High(pvals) do begin
case (pvals[i].VType) of
vtInteger: setParam('param'+its(i), pvals[i].VInteger);
vtString: setParam('param'+its(i), String(pvals[i].VString));
vtExtended: setParam('param'+its(i), pvals[i].VExtended^);
vtVariant: setParam('param'+its(i), pvals[i].VVariant^);
else setParam('param'+its(i), String(pvals[i].VString));
end;
end;
if (isSel) then qr.Open else begin
qr.ExecSQL;
qr.Close;
end;
isPrepare := false;
result := true;
if (IP='') then getIP;
end;
Вызов функции будет выглядеть, например, так:
qr.execute(['select id, pw from ldr_performer where (lower(code) = lower(?)) and (pw = ?)', dblogin, dbpw]);
Updated: 2012-02-23 11:53:40







