File indexing completed on 2024-05-12 16:35:28

0001 /* This file is part of the KDE project
0002    Copyright (C) 1998-2002 The KSpread Team <calligra-devel@kde.org>
0003    Copyright (C) 2005 Tomas Mecir <mecirt@gmail.com>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; only
0008    version 2 of the License.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018    Boston, MA 02110-1301, USA.
0019 */
0020 
0021 // built-in database functions
0022 
0023 #include "DatabaseModule.h"
0024 
0025 #include "Function.h"
0026 #include "FunctionModuleRegistry.h"
0027 #include "ValueCalc.h"
0028 #include "ValueConverter.h"
0029 
0030 using namespace Calligra::Sheets;
0031 
0032 // prototypes
0033 Value func_daverage(valVector args, ValueCalc *calc, FuncExtra *);
0034 Value func_dcount(valVector args, ValueCalc *calc, FuncExtra *);
0035 Value func_dcounta(valVector args, ValueCalc *calc, FuncExtra *);
0036 Value func_dget(valVector args, ValueCalc *calc, FuncExtra *);
0037 Value func_dmax(valVector args, ValueCalc *calc, FuncExtra *);
0038 Value func_dmin(valVector args, ValueCalc *calc, FuncExtra *);
0039 Value func_dproduct(valVector args, ValueCalc *calc, FuncExtra *);
0040 Value func_dstdev(valVector args, ValueCalc *calc, FuncExtra *);
0041 Value func_dstdevp(valVector args, ValueCalc *calc, FuncExtra *);
0042 Value func_dsum(valVector args, ValueCalc *calc, FuncExtra *);
0043 Value func_dvar(valVector args, ValueCalc *calc, FuncExtra *);
0044 Value func_dvarp(valVector args, ValueCalc *calc, FuncExtra *);
0045 Value func_getpivotdata(valVector args, ValueCalc *calc, FuncExtra *);
0046 
0047 
0048 CALLIGRA_SHEETS_EXPORT_FUNCTION_MODULE("kspreaddatabasemodule.json", DatabaseModule)
0049 
0050 
0051 DatabaseModule::DatabaseModule(QObject* parent, const QVariantList&)
0052         : FunctionModule(parent)
0053 {
0054     Function *f;
0055 
0056     f = new Function("DAVERAGE",     func_daverage);
0057     f->setParamCount(3);
0058     f->setAcceptArray();
0059     add(f);
0060     f = new Function("DCOUNT",       func_dcount);
0061     f->setParamCount(3);
0062     f->setAcceptArray();
0063     add(f);
0064     f = new Function("DCOUNTA",      func_dcounta);
0065     f->setParamCount(3);
0066     f->setAcceptArray();
0067     add(f);
0068     f = new Function("DGET",         func_dget);
0069     f->setParamCount(3);
0070     f->setAcceptArray();
0071     add(f);
0072     f = new Function("DMAX",         func_dmax);
0073     f->setParamCount(3);
0074     f->setAcceptArray();
0075     add(f);
0076     f = new Function("DMIN",         func_dmin);
0077     f->setParamCount(3);
0078     f->setAcceptArray();
0079     add(f);
0080     f = new Function("DPRODUCT",     func_dproduct);
0081     f->setParamCount(3);
0082     f->setAcceptArray();
0083     add(f);
0084     f = new Function("DSTDEV",       func_dstdev);
0085     f->setParamCount(3);
0086     f->setAcceptArray();
0087     add(f);
0088     f = new Function("DSTDEVP",      func_dstdevp);
0089     f->setParamCount(3);
0090     f->setAcceptArray();
0091     add(f);
0092     f = new Function("DSUM",         func_dsum);
0093     f->setParamCount(3);
0094     f->setAcceptArray();
0095     add(f);
0096     f = new Function("DVAR",         func_dvar);
0097     f->setParamCount(3);
0098     f->setAcceptArray();
0099     add(f);
0100     f = new Function("DVARP",        func_dvarp);
0101     f->setParamCount(3);
0102     f->setAcceptArray();
0103     add(f);
0104     f = new Function("GETPIVOTDATA", func_getpivotdata);  // partially Excel-compatible
0105     f->setParamCount(2);
0106     f->setAcceptArray();
0107     add(f);
0108 }
0109 
0110 QString DatabaseModule::descriptionFileName() const
0111 {
0112     return QString("database.xml");
0113 }
0114 
0115 
0116 int getFieldIndex(ValueCalc *calc, Value fieldName,
0117                   Value database)
0118 {
0119     if (fieldName.isNumber())
0120         return fieldName.asInteger() - 1;
0121     if (!fieldName.isString())
0122         return -1;
0123 
0124     QString fn = fieldName.asString();
0125     int cols = database.columns();
0126     for (int i = 0; i < cols; ++i)
0127         if (fn.toLower() ==
0128                 calc->conv()->asString(database.element(i, 0)).asString().toLower())
0129             return i;
0130     return -1;
0131 }
0132 
0133 // ***********************************************************
0134 // *** DBConditions class - maintains an array of conditions ***
0135 // ***********************************************************
0136 
0137 class DBConditions
0138 {
0139 public:
0140     DBConditions(ValueCalc *vc, Value database, Value conds);
0141     ~DBConditions();
0142     /** Does a specified row of the database match the given criteria?
0143     The row with column names is ignored - hence 0 specifies first data row. */
0144     bool matches(unsigned row);
0145 private:
0146     void parse(Value conds);
0147     ValueCalc *calc;
0148     QList<QList<Condition*> > cond;
0149     int rows, cols;
0150     Value db;
0151 };
0152 
0153 DBConditions::DBConditions(ValueCalc *vc, Value database,
0154                            Value conds) : calc(vc), rows(0), cols(0), db(database)
0155 {
0156     parse(conds);
0157 }
0158 
0159 DBConditions::~DBConditions()
0160 {
0161     int count = rows * cols;
0162     for (int r = 0; r < count; ++r)
0163         qDeleteAll(cond[r]);
0164 }
0165 
0166 void DBConditions::parse(Value conds)
0167 {
0168     // initialize the array
0169     rows = conds.rows() - 1;
0170     cols = db.columns();
0171     int count = rows * cols;
0172 
0173     // if rows or cols is zero or negative, then we don't need to parse anything
0174     if(count <= 0)
0175         return;
0176 
0177     for (int r = 0; r < count; ++r)
0178         cond.append(QList<Condition*>());
0179 
0180     // perform the parsing itself
0181     int cc = conds.columns();
0182     for (int c = 0; c < cc; ++c) {
0183         // first row contains column names
0184         int col = getFieldIndex(calc, conds.element(c, 0), db);
0185         if (col < 0) continue;  // failed - ignore the column
0186 
0187         // fill in the conditions for a given column name
0188         for (int r = 0; r < rows; ++r) {
0189             Value cnd = conds.element(c, r + 1);
0190             if (cnd.isEmpty()) continue;
0191             int idx = r * cols + col;
0192             //if (cond[idx]) delete cond[idx];
0193             Condition* theCond = new Condition;
0194             calc->getCond(*theCond, cnd);
0195             cond[idx].append(theCond);
0196         }
0197     }
0198 }
0199 
0200 bool DBConditions::matches(unsigned row)
0201 {
0202     if (row >= db.rows() - 1)
0203         return false;    // out of range
0204 
0205     // we have a match, if at least one row of criteria matches
0206     for (int r = 0; r < rows; ++r) {
0207         // within a row, all criteria must match
0208         bool match = true;
0209         for (int c = 0; c < cols; ++c) {
0210             int idx = r * cols + c;
0211             if (cond[idx].isEmpty()) continue;
0212             for (int i = 0; i < cond[idx].size(); i++) {
0213                 if (!calc->matches(*cond[idx][i], db.element(c, row + 1))) {
0214                     match = false;  // didn't match
0215                     break;
0216                 }
0217             }
0218         }
0219         if (match)  // all conditions in this row matched
0220             return true;
0221     }
0222 
0223     // no row matched
0224     return false;
0225 }
0226 
0227 
0228 // *******************************************
0229 // *** Function implementations start here ***
0230 // *******************************************
0231 
0232 // Function: DSUM
0233 Value func_dsum(valVector args, ValueCalc *calc, FuncExtra *)
0234 {
0235     Value database = args[0];
0236     Value conditions = args[2];
0237     int fieldIndex = getFieldIndex(calc, args[1], database);
0238     if (fieldIndex < 0)
0239         return Value::errorVALUE();
0240 
0241     DBConditions conds(calc, database, conditions);
0242 
0243     int rows = database.rows() - 1;  // first row contains column names
0244     Value res(0.0);
0245     for (int r = 0; r < rows; ++r)
0246         if (conds.matches(r)) {
0247             Value val = database.element(fieldIndex, r + 1);
0248             // include this value in the result
0249             if (!val.isEmpty())
0250                 res = calc->add(res, val);
0251         }
0252 
0253     return res;
0254 }
0255 
0256 // Function: DAVERAGE
0257 Value func_daverage(valVector args, ValueCalc *calc, FuncExtra *)
0258 {
0259     Value database = args[0];
0260     Value conditions = args[2];
0261     int fieldIndex = getFieldIndex(calc, args[1], database);
0262     if (fieldIndex < 0)
0263         return Value::errorVALUE();
0264 
0265     DBConditions conds(calc, database, conditions);
0266 
0267     int rows = database.rows() - 1;  // first row contains column names
0268     Value res;
0269     int count = 0;
0270     for (int r = 0; r < rows; ++r)
0271         if (conds.matches(r)) {
0272             Value val = database.element(fieldIndex, r + 1);
0273             // include this value in the result
0274             if (!val.isEmpty()) {
0275                 res = calc->add(res, val);
0276                 count++;
0277             }
0278         }
0279     if (count) res = calc->div(res, count);
0280     return res;
0281 }
0282 
0283 // Function: DCOUNT
0284 Value func_dcount(valVector args, ValueCalc *calc, FuncExtra *)
0285 {
0286     Value database = args[0];
0287     Value conditions = args[2];
0288     int fieldIndex = getFieldIndex(calc, args[1], database);
0289 
0290     DBConditions conds(calc, database, conditions);
0291 
0292     int rows = database.rows() - 1;  // first row contains column names
0293     int count = 0;
0294     for (int r = 0; r < rows; ++r)
0295         if (conds.matches(r)) {
0296             // fieldIndex is optional, if no field is specified count all rows matching the conditions
0297             if (fieldIndex < 0)
0298                 count++;
0299             else {
0300                 Value val = database.element(fieldIndex, r + 1);
0301                 // include this value in the result
0302                 if ((!val.isEmpty()) && (!val.isBoolean()) && (!val.isString()))
0303                     count++;
0304             }
0305         }
0306 
0307     return Value(count);
0308 }
0309 
0310 // Function: DCOUNTA
0311 Value func_dcounta(valVector args, ValueCalc *calc, FuncExtra *)
0312 {
0313     Value database = args[0];
0314     Value conditions = args[2];
0315     int fieldIndex = getFieldIndex(calc, args[1], database);
0316 
0317     DBConditions conds(calc, database, conditions);
0318 
0319     int rows = database.rows() - 1;  // first row contains column names
0320     int count = 0;
0321     for (int r = 0; r < rows; ++r)
0322         if (conds.matches(r)) {
0323             // fieldIndex is optional, if no field is specified count all rows matching the conditions
0324             if (fieldIndex < 0)
0325                 count++;
0326             else {
0327                 Value val = database.element(fieldIndex, r + 1);
0328                 // include this value in the result
0329                 if (!val.isEmpty())
0330                     count++;
0331             }
0332         }
0333 
0334     return Value(count);
0335 }
0336 
0337 // Function: DGET
0338 Value func_dget(valVector args, ValueCalc *calc, FuncExtra *)
0339 {
0340     Value database = args[0];
0341     Value conditions = args[2];
0342     int fieldIndex = getFieldIndex(calc, args[1], database);
0343     if (fieldIndex < 0)
0344         return Value::errorVALUE();
0345 
0346     DBConditions conds(calc, database, conditions);
0347 
0348     bool match = false;
0349     Value result = Value::errorVALUE();
0350     int rows = database.rows() - 1;  // first row contains column names
0351     for (int r = 0; r < rows; ++r)
0352         if (conds.matches(r)) {
0353             if (match) {
0354                 // error on multiple matches
0355                 result = Value::errorVALUE();
0356                 break;
0357             }
0358             result = database.element(fieldIndex, r + 1);
0359             match = true;
0360         }
0361 
0362     return result;
0363 }
0364 
0365 // Function: DMAX
0366 Value func_dmax(valVector args, ValueCalc *calc, FuncExtra *)
0367 {
0368     Value database = args[0];
0369     Value conditions = args[2];
0370     int fieldIndex = getFieldIndex(calc, args[1], database);
0371     if (fieldIndex < 0)
0372         return Value::errorVALUE();
0373 
0374     DBConditions conds(calc, database, conditions);
0375 
0376     int rows = database.rows() - 1;  // first row contains column names
0377     Value res;
0378     bool got = false;
0379     for (int r = 0; r < rows; ++r)
0380         if (conds.matches(r)) {
0381             Value val = database.element(fieldIndex, r + 1);
0382             // include this value in the result
0383             if (!val.isEmpty()) {
0384                 if (!got) {
0385                     res = val;
0386                     got = true;
0387                 } else if (calc->greater(val, res))
0388                     res = val;
0389             }
0390         }
0391 
0392     return res;
0393 }
0394 
0395 // Function: DMIN
0396 Value func_dmin(valVector args, ValueCalc *calc, FuncExtra *)
0397 {
0398     Value database = args[0];
0399     Value conditions = args[2];
0400     int fieldIndex = getFieldIndex(calc, args[1], database);
0401     if (fieldIndex < 0)
0402         return Value::errorVALUE();
0403 
0404     DBConditions conds(calc, database, conditions);
0405 
0406     int rows = database.rows() - 1;  // first row contains column names
0407     Value res;
0408     bool got = false;
0409     for (int r = 0; r < rows; ++r)
0410         if (conds.matches(r)) {
0411             Value val = database.element(fieldIndex, r + 1);
0412             // include this value in the result
0413             if (!val.isEmpty()) {
0414                 if (!got) {
0415                     res = val;
0416                     got = true;
0417                 } else if (calc->lower(val, res))
0418                     res = val;
0419             }
0420         }
0421 
0422     return res;
0423 }
0424 
0425 // Function: DPRODUCT
0426 Value func_dproduct(valVector args, ValueCalc *calc, FuncExtra *)
0427 {
0428     Value database = args[0];
0429     Value conditions = args[2];
0430     int fieldIndex = getFieldIndex(calc, args[1], database);
0431     if (fieldIndex < 0)
0432         return Value::errorVALUE();
0433 
0434     DBConditions conds(calc, database, conditions);
0435 
0436     int rows = database.rows() - 1;  // first row contains column names
0437     Value res = Value((double)1.0);
0438     bool got = false;
0439     for (int r = 0; r < rows; ++r)
0440         if (conds.matches(r)) {
0441             Value val = database.element(fieldIndex, r + 1);
0442             // include this value in the result
0443             if (!val.isEmpty()) {
0444                 got = true;
0445                 res = calc->mul(res, val);
0446             }
0447         }
0448     if (got)
0449         return res;
0450     return Value::errorVALUE();
0451 }
0452 
0453 // Function: DSTDEV
0454 Value func_dstdev(valVector args, ValueCalc *calc, FuncExtra *)
0455 {
0456     // sqrt (dvar)
0457     return calc->sqrt(func_dvar(args, calc, 0));
0458 }
0459 
0460 // Function: DSTDEVP
0461 Value func_dstdevp(valVector args, ValueCalc *calc, FuncExtra *)
0462 {
0463     // sqrt (dvarp)
0464     return calc->sqrt(func_dvarp(args, calc, 0));
0465 }
0466 
0467 // Function: DVAR
0468 Value func_dvar(valVector args, ValueCalc *calc, FuncExtra *)
0469 {
0470     Value database = args[0];
0471     Value conditions = args[2];
0472     int fieldIndex = getFieldIndex(calc, args[1], database);
0473     if (fieldIndex < 0)
0474         return Value::errorVALUE();
0475 
0476     DBConditions conds(calc, database, conditions);
0477 
0478     int rows = database.rows() - 1;  // first row contains column names
0479     Value avg;
0480     int count = 0;
0481     for (int r = 0; r < rows; ++r)
0482         if (conds.matches(r)) {
0483             Value val = database.element(fieldIndex, r + 1);
0484             // include this value in the result
0485             if (!val.isEmpty()) {
0486                 avg = calc->add(avg, val);
0487                 count++;
0488             }
0489         }
0490     if (count < 2) return Value::errorDIV0();
0491     avg = calc->div(avg, count);
0492 
0493     Value res;
0494     for (int r = 0; r < rows; ++r)
0495         if (conds.matches(r)) {
0496             Value val = database.element(fieldIndex, r + 1);
0497             // include this value in the result
0498             if (!val.isEmpty())
0499                 res = calc->add(res, calc->sqr(calc->sub(val, avg)));
0500         }
0501 
0502     // res / (count-1)
0503     return calc->div(res, count - 1);
0504 }
0505 
0506 // Function: DVARP
0507 Value func_dvarp(valVector args, ValueCalc *calc, FuncExtra *)
0508 {
0509     Value database = args[0];
0510     Value conditions = args[2];
0511     int fieldIndex = getFieldIndex(calc, args[1], database);
0512     if (fieldIndex < 0)
0513         return Value::errorVALUE();
0514 
0515     DBConditions conds(calc, database, conditions);
0516 
0517     int rows = database.rows() - 1;  // first row contains column names
0518     Value avg;
0519     int count = 0;
0520     for (int r = 0; r < rows; ++r)
0521         if (conds.matches(r)) {
0522             Value val = database.element(fieldIndex, r + 1);
0523             // include this value in the result
0524             if (!val.isEmpty()) {
0525                 avg = calc->add(avg, val);
0526                 count++;
0527             }
0528         }
0529     if (count == 0) return Value::errorDIV0();
0530     avg = calc->div(avg, count);
0531 
0532     Value res;
0533     for (int r = 0; r < rows; ++r)
0534         if (conds.matches(r)) {
0535             Value val = database.element(fieldIndex, r + 1);
0536             // include this value in the result
0537             if (!val.isEmpty())
0538                 res = calc->add(res, calc->sqr(calc->sub(val, avg)));
0539         }
0540 
0541     // res / count
0542     return calc->div(res, count);
0543 }
0544 
0545 // Function: GETPIVOTDATA
0546 // FIXME implement more things with this, see Excel !
0547 Value func_getpivotdata(valVector args, ValueCalc *calc, FuncExtra *)
0548 {
0549     Value database = args[0];
0550     int fieldIndex = getFieldIndex(calc, args[1], database);
0551     if (fieldIndex < 0)
0552         return Value::errorVALUE();
0553     // the row at the bottom
0554     int row = database.rows() - 1;
0555 
0556     return database.element(fieldIndex, row);
0557 }
0558 
0559 #include "database.moc"