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"