Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 4
0
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;
}