int KexiDB::rowCount(KexiDB::QuerySchema& querySchema) { //! @todo does not work with non-SQL data sources if (!querySchema.connection()) { KexiDBWarn << "KexiDB::rowsCount(const KexiDB::QuerySchema&): no querySchema.connection() !"; return -1; } int count = -1; //will be changed only on success of querySingleNumber() querySchema.connection()->querySingleNumber( QString::fromLatin1("SELECT COUNT(*) FROM (") + querySchema.connection()->selectStatement(querySchema) + ")", count ); return count; }
void KexiComboBoxTableEdit::createInternalEditor(KexiDB::QuerySchema& schema) { if (!m_column->visibleLookupColumnInfo() || d->visibleTableViewColumn/*sanity*/) return; const KexiDB::Field::Type t = m_column->visibleLookupColumnInfo()->field->type(); //! @todo subtype? KexiCellEditorFactoryItem *item = KexiCellEditorFactory::item(t); if (!item || item->className() == "KexiInputTableEdit") return; //unsupported type or there is no need to use subeditor for KexiInputTableEdit //special cases: BLOB, Bool datatypes //! @todo //find real type to display KexiDB::QueryColumnInfo *ci = m_column->visibleLookupColumnInfo(); KexiDB::QueryColumnInfo *visibleLookupColumnInfo = 0; if (ci->indexForVisibleLookupValue() != -1) { //Lookup field is defined visibleLookupColumnInfo = schema.expandedOrInternalField(ci->indexForVisibleLookupValue()); } d->visibleTableViewColumn = new KexiDB::TableViewColumn(schema, *ci, visibleLookupColumnInfo); //! todo set d->internalEditor visible and use it to enable data entering by hand d->internalEditor = KexiCellEditorFactory::createEditor(*d->visibleTableViewColumn, 0); m_lineedit->hide(); }
//static QList<QVariant> KexiQueryParameters::getParameters(QWidget *parent, const KexiDB::Driver &driver, KexiDB::QuerySchema& querySchema, bool &ok) { Q_UNUSED(driver); ok = false; const KexiDB::QuerySchemaParameterList params(querySchema.parameters()); QList<QVariant> values; const QString caption(i18nc("Enter Query Parameter Value", "Enter Parameter Value")); for (KexiDB::QuerySchemaParameterListConstIterator it = params.constBegin(); it != params.constEnd(); ++it) { switch ((*it).type) { case KexiDB::Field::Byte: case KexiDB::Field::ShortInteger: case KexiDB::Field::Integer: case KexiDB::Field::BigInteger: { //! @todo problem for ranges in case of BigInteger - will disappear when we remove use of KInputDialog int minValue, maxValue; //! @todo add support for unsigned parameter here KexiDB::getLimitsForType((*it).type, minValue, maxValue); const int result = KInputDialog::getInteger( caption, (*it).message, 0, minValue, maxValue, 1/*step*/, 10/*base*/, &ok, parent); if (!ok) return QList<QVariant>(); //cancelled values.append(result); break; } case KexiDB::Field::Boolean: { QStringList list; list << i18nc("Boolean True - Yes", "Yes") << i18nc("Boolean False - No", "No"); const QString result = KInputDialog::getItem( caption, (*it).message, list, 0/*current*/, false /*!editable*/, &ok, parent); if (!ok || result.isEmpty()) return QList<QVariant>(); //cancelled values.append(result == list.first()); break; } case KexiDB::Field::Date: { KexiDateFormatter df; const QString result = KInputDialog::getText( caption, (*it).message, QString(), &ok, parent, 0/*name*/, //! @todo add validator 0/*validator*/, df.inputMask()); if (!ok) return QList<QVariant>(); //cancelled values.append(df.fromString(result)); break; } case KexiDB::Field::DateTime: { KexiDateFormatter df; KexiTimeFormatter tf; const QString result = KInputDialog::getText( caption, (*it).message, QString(), &ok, parent, 0/*name*/, //! @todo add validator 0/*validator*/, KexiDateTimeFormatter::inputMask(df, tf)); if (!ok) return QList<QVariant>(); //cancelled values.append(KexiDateTimeFormatter::fromString(df, tf, result)); break; } case KexiDB::Field::Time: { KexiTimeFormatter tf; const QString result = KInputDialog::getText( caption, (*it).message, QString(), &ok, parent, 0/*name*/, //! @todo add validator 0/*validator*/, tf.inputMask()); if (!ok) return QList<QVariant>(); //cancelled values.append(tf.fromString(result)); break; } case KexiDB::Field::Float: case KexiDB::Field::Double: { // KInputDialog::getDouble() does not work well, use getText and double validator KDoubleValidator validator(0); const QString textResult( KInputDialog::getText(caption, (*it).message, QString(), &ok, parent, &validator)); if (!ok || textResult.isEmpty()) return QList<QVariant>(); //cancelled //! @todo this value will be still rounded: consider storing them as a decimal type //! (e.g. using a special qint64+decimalplace class) const double result = textResult.toDouble(&ok); //this is also good for float (to avoid rounding) if (!ok) return QList<QVariant>(); values.append(result); break; } case KexiDB::Field::Text: case KexiDB::Field::LongText: { const QString result = KInputDialog::getText( caption, (*it).message, QString(), &ok, parent); if (!ok) return QList<QVariant>(); //cancelled values.append(result); break; } case KexiDB::Field::BLOB: { //! @todo BLOB input unsupported values.append(QByteArray()); } default: kWarning() << "KexiQueryParameters::getParameters() unsupported type " << KexiDB::Field::typeName((*it).type) << " for parameter \"" << (*it).message << "\" - aborting query execution!"; return QList<QVariant>(); } } ok = true; return values; }
bool KexiCSVExport::exportData(KexiDB::TableOrQuerySchema& tableOrQuery, const Options& options, int rowCount, QTextStream *predefinedTextStream) { KexiDB::Connection* conn = tableOrQuery.connection(); if (!conn) return false; if (rowCount == -1) rowCount = KexiDB::rowCount(tableOrQuery); if (rowCount == -1) return false; //! @todo move this to non-GUI location so it can be also used via command line //! @todo add a "finish" page with a progressbar. //! @todo look at rowCount whether the data is really large; //! if so: avoid copying to clipboard (or ask user) because of system memory //! @todo OPTIMIZATION: use fieldsExpanded(true /*UNIQUE*/) //! @todo OPTIMIZATION? (avoid multiple data retrieving) look for already fetched data within KexiProject.. KexiDB::QuerySchema* query = tableOrQuery.query(); if (!query) query = tableOrQuery.table()->query(); KexiDB::QueryColumnInfo::Vector fields( query->fieldsExpanded( KexiDB::QuerySchema::WithInternalFields ) ); QString buffer; KSaveFile *kSaveFile = 0; QTextStream *stream = 0; const bool copyToClipboard = options.mode==Clipboard; if (copyToClipboard) { //! @todo (during exporting): enlarge bufSize by factor of 2 when it became too small uint bufSize = QMIN((rowCount<0 ? 10 : rowCount) * fields.count() * 20, 128000); buffer.reserve( bufSize ); if (buffer.capacity() < bufSize) { kdWarning() << "KexiCSVExportWizard::exportData() cannot allocate memory for " << bufSize << " characters" << endl; return false; } } else { if (predefinedTextStream) { stream = predefinedTextStream; } else { if (options.fileName.isEmpty()) {//sanity kdWarning() << "KexiCSVExportWizard::exportData(): fname is empty" << endl; return false; } kSaveFile = new KSaveFile(options.fileName); if (0 == kSaveFile->status()) stream = kSaveFile->textStream(); if (0 != kSaveFile->status() || !stream) {//sanity kdWarning() << "KexiCSVExportWizard::exportData(): status != 0 or stream == 0" << endl; delete kSaveFile; return false; } } } //! @todo escape strings #define _ERR \ delete [] isText; \ if (kSaveFile) { kSaveFile->abort(); delete kSaveFile; } \ return false #define APPEND(what) \ if (copyToClipboard) buffer.append(what); else (*stream) << (what) // line endings should be as in RFC 4180 #define CSV_EOLN "\r\n" // 0. Cache information const uint fieldsCount = query->fieldsExpanded().count(); //real fields count without internals const QCString delimiter( options.delimiter.left(1).latin1() ); const bool hasTextQuote = !options.textQuote.isEmpty(); const QString textQuote( options.textQuote.left(1) ); const QCString escapedTextQuote( (textQuote + textQuote).latin1() ); //ok? //cache for faster checks bool *isText = new bool[fieldsCount]; bool *isDateTime = new bool[fieldsCount]; bool *isTime = new bool[fieldsCount]; bool *isBLOB = new bool[fieldsCount]; uint *visibleFieldIndex = new uint[fieldsCount]; // bool isInteger[fieldsCount]; //cache for faster checks // bool isFloatingPoint[fieldsCount]; //cache for faster checks for (uint i=0; i<fieldsCount; i++) { KexiDB::QueryColumnInfo* ci; const int indexForVisibleLookupValue = fields[i]->indexForVisibleLookupValue(); if (-1 != indexForVisibleLookupValue) { ci = query->expandedOrInternalField( indexForVisibleLookupValue ); visibleFieldIndex[i] = indexForVisibleLookupValue; } else { ci = fields[i]; visibleFieldIndex[i] = i; } isText[i] = ci->field->isTextType(); isDateTime[i] = ci->field->type()==KexiDB::Field::DateTime; isTime[i] = ci->field->type()==KexiDB::Field::Time; isBLOB[i] = ci->field->type()==KexiDB::Field::BLOB; // isInteger[i] = fields[i]->field->isIntegerType() // || fields[i]->field->type()==KexiDB::Field::Boolean; // isFloatingPoint[i] = fields[i]->field->isFPNumericType(); } // 1. Output column names if (options.addColumnNames) { for (uint i=0; i<fieldsCount; i++) { if (i>0) APPEND( delimiter ); if (hasTextQuote){ APPEND( textQuote + fields[i]->captionOrAliasOrName().replace(textQuote, escapedTextQuote) + textQuote ); } else { APPEND( fields[i]->captionOrAliasOrName() ); } } APPEND(CSV_EOLN); } KexiGUIMessageHandler handler; KexiDB::Cursor *cursor = conn->executeQuery(*query); if (!cursor) { handler.showErrorMessage(conn); _ERR; } for (cursor->moveFirst(); !cursor->eof() && !cursor->error(); cursor->moveNext()) { const uint realFieldCount = QMIN(cursor->fieldCount(), fieldsCount); for (uint i=0; i<realFieldCount; i++) { const uint real_i = visibleFieldIndex[i]; if (i>0) APPEND( delimiter ); if (cursor->value(real_i).isNull()) continue; if (isText[real_i]) { if (hasTextQuote) APPEND( textQuote + QString(cursor->value(real_i).toString()).replace(textQuote, escapedTextQuote) + textQuote ); else APPEND( cursor->value(real_i).toString() ); } else if (isDateTime[real_i]) { //avoid "T" in ISO DateTime APPEND( cursor->value(real_i).toDateTime().date().toString(Qt::ISODate)+" " + cursor->value(real_i).toDateTime().time().toString(Qt::ISODate) ); } else if (isTime[real_i]) { //time is temporarily stored as null date + time... APPEND( cursor->value(real_i).toTime().toString(Qt::ISODate) ); } else if (isBLOB[real_i]) { //BLOB is escaped in a special way if (hasTextQuote) //! @todo add options to suppport other types from KexiDB::BLOBEscapingType enum... APPEND( textQuote + KexiDB::escapeBLOB(cursor->value(real_i).toByteArray(), KexiDB::BLOBEscapeHex) + textQuote ); else APPEND( KexiDB::escapeBLOB(cursor->value(real_i).toByteArray(), KexiDB::BLOBEscapeHex) ); } else {//other types APPEND( cursor->value(real_i).toString() ); } } APPEND(CSV_EOLN); } if (copyToClipboard) buffer.squeeze(); if (!conn->deleteCursor(cursor)) { handler.showErrorMessage(conn); _ERR; } if (copyToClipboard) kapp->clipboard()->setText(buffer, QClipboard::Clipboard); delete [] isText; delete [] isDateTime; delete [] isTime; delete [] isBLOB; delete [] visibleFieldIndex; if (kSaveFile) { if (!kSaveFile->close()) { kdWarning() << "KexiCSVExportWizard::exportData(): error close(); status == " << kSaveFile->status() << endl; } delete kSaveFile; } return true; }