File indexing completed on 2024-05-05 16:47:14
0001 /* This file is part of the KDE project 0002 Copyright (C) 2003 Adam Pigg <adam@piggz.co.uk> 0003 Copyright (C) 2010-2015 Jarosław Staniek <staniek@kde.org> 0004 0005 This program 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; either 0008 version 2 of the License, or (at your option) any later version. 0009 0010 This program 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 program; see the file COPYING. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "PostgresqlDriver.h" 0022 0023 #include "KDbConnection.h" 0024 #include "KDbDriverManager.h" 0025 #include "KDbDriverBehavior.h" 0026 #include "KDbExpression.h" 0027 #include "KDb.h" 0028 0029 #include "PostgresqlConnection.h" 0030 0031 #include <KPluginFactory> 0032 0033 #include <libpq-fe.h> 0034 0035 KDB_DRIVER_PLUGIN_FACTORY(PostgresqlDriver, "kdb_postgresqldriver.json") 0036 0037 PostgresqlDriver::PostgresqlDriver(QObject *parent, const QVariantList &args) 0038 : KDbDriver(parent, args) 0039 { 0040 KDbDriverBehavior *beh = behavior(); 0041 beh->features = SingleTransactions | CursorForward | CursorBackward; 0042 //! @todo enable this when KDb supports multiple: beh->features = MultipleTransactions | CursorForward | CursorBackward; 0043 0044 beh->UNSIGNED_TYPE_KEYWORD = QString(); 0045 beh->ROW_ID_FIELD_NAME = QLatin1String("oid"); 0046 beh->SPECIAL_AUTO_INCREMENT_DEF = false; 0047 beh->AUTO_INCREMENT_TYPE = QLatin1String("SERIAL"); 0048 beh->AUTO_INCREMENT_FIELD_OPTION = QString(); 0049 beh->AUTO_INCREMENT_PK_FIELD_OPTION = QLatin1String("PRIMARY KEY"); 0050 beh->ALWAYS_AVAILABLE_DATABASE_NAME = QLatin1String("template1"); 0051 beh->OPENING_QUOTATION_MARK_BEGIN_FOR_IDENTIFIER = '"'; 0052 beh->CLOSING_QUOTATION_MARK_BEGIN_FOR_IDENTIFIER = '"'; 0053 beh->LIKE_OPERATOR = QLatin1String("ILIKE"); 0054 // Use SQL compliant TRUE or FALSE as described 0055 // at https://www.postgresql.org/docs/8.0/interactive/datatype-boolean.html 0056 // 1 or 0 does not work. 0057 beh->BOOLEAN_TRUE_LITERAL = QLatin1String("TRUE"); 0058 beh->BOOLEAN_FALSE_LITERAL = QLatin1String("FALSE"); 0059 beh->USE_TEMPORARY_DATABASE_FOR_CONNECTION_IF_NEEDED = true; 0060 beh->GET_TABLE_NAMES_SQL = KDbEscapedString( 0061 "SELECT table_name FROM information_schema.tables WHERE " 0062 "table_type='BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema')"); 0063 0064 initDriverSpecificKeywords(m_keywords); 0065 initPgsqlToKDbMap(); 0066 0067 //predefined properties 0068 //https://www.postgresql.org/docs/9.5/static/libpq-misc.html#LIBPQ-PQLIBVERSION 0069 //! @todo use QLibrary to resolve PQlibVersion 0070 beh->properties.insert("client_library_version", PQlibVersion()); 0071 //! @todo pgsql default_server_encoding: should be a property of connection 0072 //beh->properties["default_server_encoding"] = QString(); 0073 0074 beh->typeNames[KDbField::Byte] = QLatin1String("SMALLINT"); 0075 beh->typeNames[KDbField::ShortInteger] = QLatin1String("SMALLINT"); 0076 beh->typeNames[KDbField::Integer] = QLatin1String("INTEGER"); 0077 beh->typeNames[KDbField::BigInteger] = QLatin1String("BIGINT"); 0078 beh->typeNames[KDbField::Boolean] = QLatin1String("BOOLEAN"); 0079 beh->typeNames[KDbField::Date] = QLatin1String("DATE"); 0080 beh->typeNames[KDbField::DateTime] = QLatin1String("TIMESTAMP"); 0081 beh->typeNames[KDbField::Time] = QLatin1String("TIME"); 0082 beh->typeNames[KDbField::Float] = QLatin1String("REAL"); 0083 beh->typeNames[KDbField::Double] = QLatin1String("DOUBLE PRECISION"); 0084 beh->typeNames[KDbField::Text] = QLatin1String("CHARACTER VARYING"); 0085 beh->typeNames[KDbField::LongText] = QLatin1String("TEXT"); 0086 beh->typeNames[KDbField::BLOB] = QLatin1String("BYTEA"); 0087 } 0088 0089 PostgresqlDriver::~PostgresqlDriver() 0090 { 0091 } 0092 0093 QString PostgresqlDriver::sqlTypeName(KDbField::Type type, const KDbField &field) const 0094 { 0095 if (type == KDbField::Null) { 0096 return QLatin1String("NULL"); 0097 } 0098 if (type == KDbField::Float || type == KDbField::Double) { 0099 if (field.precision() > 0) { 0100 return QLatin1String("NUMERIC"); 0101 } 0102 } 0103 return KDbDriver::sqlTypeName(type, field); 0104 } 0105 0106 KDbConnection* PostgresqlDriver::drv_createConnection(const KDbConnectionData& connData, 0107 const KDbConnectionOptions &options) 0108 { 0109 return new PostgresqlConnection(this, connData, options); 0110 } 0111 0112 bool PostgresqlDriver::isSystemObjectName(const QString& name) const 0113 { 0114 Q_UNUSED(name); 0115 return false; 0116 } 0117 0118 bool PostgresqlDriver::drv_isSystemFieldName(const QString& name) const 0119 { 0120 Q_UNUSED(name); 0121 return false; 0122 } 0123 0124 bool PostgresqlDriver::isSystemDatabaseName(const QString& name) const 0125 { 0126 return 0 == name.compare(QLatin1String("template1"), Qt::CaseInsensitive) 0127 || 0 == name.compare(QLatin1String("template0"), Qt::CaseInsensitive) 0128 || 0 == name.compare(QLatin1String("postgres"), Qt::CaseInsensitive); 0129 } 0130 0131 KDbEscapedString PostgresqlDriver::escapeString(const QString& str) const 0132 { 0133 //Cannot use libpq escape functions as they require a db connection 0134 //to escape using the char encoding of the database 0135 //see https://www.postgresql.org/docs/8.1/static/libpq-exec.html#LIBPQ-EXEC-ESCAPE-STRING 0136 return KDbEscapedString("E'") 0137 + KDbEscapedString(str).replace("\\", "\\\\").replace("'", "\\\'") 0138 + "'"; 0139 } 0140 0141 KDbEscapedString PostgresqlDriver::escapeString(const QByteArray& str) const 0142 { 0143 //Cannot use libpq escape functions as they require a db connection 0144 //to escape using the char encoding of the database 0145 //see https://www.postgresql.org/docs/8.1/static/libpq-exec.html#LIBPQ-EXEC-ESCAPE-STRING 0146 return KDbEscapedString("'") 0147 + QByteArray(str).replace("\\", "\\\\").replace("'", "\\\'") 0148 + "'"; 0149 } 0150 0151 QString PostgresqlDriver::drv_escapeIdentifier(const QString& str) const 0152 { 0153 return QString(str).replace(QLatin1Char('"'), QLatin1String("\"\"")); 0154 } 0155 0156 QByteArray PostgresqlDriver::drv_escapeIdentifier(const QByteArray& str) const 0157 { 0158 return QByteArray(str).replace('"', "\"\""); 0159 } 0160 0161 KDbEscapedString PostgresqlDriver::escapeBLOB(const QByteArray& array) const 0162 { 0163 return KDbEscapedString(KDb::escapeBLOB(array, KDb::BLOBEscapingType::ByteaHex)); 0164 } 0165 0166 KDbEscapedString PostgresqlDriver::hexFunctionToString(const KDbNArgExpression &args, 0167 KDbQuerySchemaParameterValueListIterator* params, 0168 KDb::ExpressionCallStack* callStack) const 0169 { 0170 Q_ASSERT(args.argCount() == 1); 0171 return KDbEscapedString("UPPER(ENCODE(%1, 'hex'))").arg(args.arg(0).toString(this, params, callStack)); 0172 } 0173 0174 KDbEscapedString PostgresqlDriver::ifnullFunctionToString(const KDbNArgExpression &args, 0175 KDbQuerySchemaParameterValueListIterator* params, 0176 KDb::ExpressionCallStack* callStack) const 0177 { 0178 return KDbFunctionExpression::toString(QLatin1String("COALESCE"), this, args, params, callStack); 0179 } 0180 0181 KDbEscapedString PostgresqlDriver::lengthFunctionToString(const KDbNArgExpression &args, 0182 KDbQuerySchemaParameterValueListIterator* params, 0183 KDb::ExpressionCallStack* callStack) const 0184 { 0185 Q_ASSERT(args.argCount() == 1); 0186 if (args.arg(0).type() == KDbField::BLOB) { 0187 return KDbFunctionExpression::toString(QLatin1String("OCTET_LENGTH"), this, args, params, callStack); 0188 } 0189 return KDbDriver::lengthFunctionToString(args, params, callStack); // default 0190 } 0191 0192 KDbEscapedString PostgresqlDriver::greatestOrLeastFunctionToString(const QString &name, 0193 const KDbNArgExpression &args, 0194 KDbQuerySchemaParameterValueListIterator* params, 0195 KDb::ExpressionCallStack* callStack) const 0196 { 0197 return KDbFunctionExpression::greatestOrLeastFunctionUsingCaseToString( 0198 name, this, args, params, callStack); 0199 } 0200 0201 KDbEscapedString PostgresqlDriver::unicodeFunctionToString( 0202 const KDbNArgExpression &args, 0203 KDbQuerySchemaParameterValueListIterator* params, 0204 KDb::ExpressionCallStack* callStack) const 0205 { 0206 Q_ASSERT(args.argCount() == 1); 0207 return KDbEscapedString("ASCII(%1)").arg(args.arg(0).toString(this, params, callStack)); 0208 } 0209 0210 #include "PostgresqlDriver.moc"