File indexing completed on 2024-05-05 16:47:17

0001 /* This file is part of the KDE project
0002    Copyright (C) 2007 Sharan Rao <sharanrao@gmail.com>
0003 
0004 This program is free software; you can redistribute it and/or
0005 modify it under the terms of the GNU Library General Public
0006 License as published by the Free Software Foundation; either
0007 version 2 of the License, or (at your option) any later version.
0008 
0009 This program is distributed in the hope that it will be useful,
0010 but WITHOUT ANY WARRANTY; without even the implied warranty of
0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012 Library General Public License for more details.
0013 
0014 You should have received a copy of the GNU Library General Public License
0015 along with this program; see the file COPYING. If not, write to
0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include <QByteArray>
0021 #include <QStringList>
0022 #include <QApplication>
0023 #include <QFile>
0024 #include <QTemporaryFile>
0025 
0026 #include "SybaseConnection_p.h"
0027 
0028 #include "KDbConnectionData.h"
0029 
0030 QMap<DBPROCESS*, SybaseConnectionInternal*> SybaseConnectionInternal::dbProcessConnectionMap;
0031 
0032 
0033 int connectionMessageHandler(DBPROCESS* dbproc, DBINT msgno, int msgstate, int severity,
0034                              char* msgtext, char* srvname, char* procname, int line)
0035 {
0036     if (!dbproc) {
0037         return 0;
0038     }
0039 
0040     SybaseConnectionInternal* conn = SybaseConnectionInternal::dbProcessConnectionMap[dbproc];
0041     if (conn)
0042         conn->messageHandler(msgno, msgstate, severity, msgtext, srvname, procname, line);
0043 
0044     return (0);
0045 }
0046 
0047 SybaseConnectionInternal::SybaseConnectionInternal(KDbConnection* connection)
0048         : ConnectionInternal(connection)
0049         , dbProcess(0)
0050         , res(0)
0051 {
0052 }
0053 
0054 SybaseConnectionInternal::~SybaseConnectionInternal()
0055 {
0056     if (sybase_owned && dbProcess) {
0057         dbclose(dbProcess);
0058         dbProcess = 0;
0059     }
0060 }
0061 
0062 void SybaseConnectionInternal::storeResult()
0063 {
0064     //sybaseDebug() << "Store Result!!";
0065     // all message numbers and message texts were handled in the messageHandler
0066     // so don't do anything here
0067 }
0068 
0069 void SybaseConnectionInternal::messageHandler(DBINT msgno, int msgstate, int severity, char* msgtext, char* srvname, char* procname, int line)
0070 {
0071 
0072     Q_UNUSED(msgstate);
0073     Q_UNUSED(severity);
0074     Q_UNUSED(srvname);
0075     Q_UNUSED(procname);
0076     Q_UNUSED(line);
0077 
0078     res = msgno;
0079     errmsg = QString::fromLatin1(msgtext);
0080     //sybaseDebug() << "Message Handler" << res << errmsg;
0081 }
0082 
0083 bool SybaseConnectionInternal::db_connect(const KDbConnectionData& data)
0084 {
0085     if (dbinit() == FAIL)
0086         return false;
0087 
0088     // set message handler
0089     dbmsghandle(connectionMessageHandler);
0090 
0091     QByteArray localSocket;
0092     QString hostName = data.hostName;
0093 
0094 
0095     if (data.serverName.isEmpty()) {
0096         sybaseWarning() << "Can't connect without server name";
0097         return false;
0098     }
0099 
0100 
0101     // set Error.handlers
0102     // set message handlers
0103 
0104     LOGINREC* login;
0105 
0106     login = dblogin();
0107     if (!login) {
0108         //dbexit();
0109         return false;
0110     }
0111 
0112     // umm, copied from pqxx driver.
0113     if (hostName.isEmpty() || 0 == hostName.compare(QLatin1String("localhost"), Qt::CaseInsensitive)) {
0114         if (data.useLocalSocketFile) {
0115             if (data.localSocketFileName.isEmpty()) {
0116                 QStringList sockets;
0117 #ifndef Q_OS_WIN
0118                 sockets.append("/tmp/s.sybase.2638");
0119 
0120                 foreach(const QString& socket, sockets) {
0121                     if (QFile(socket).exists()) {
0122                         localSocket = socket.toLatin1();
0123                         break;
0124                     }
0125                 }
0126 #endif
0127             } else
0128                 localSocket = QFile::encodeName(data.localSocketFileName);
0129         } else {
0130             //we're not using local socket
0131             hostName = "127.0.0.1";
0132         }
0133     }
0134 
0135     QTemporaryFile confFile(QDir::tempPath() + QLatin1String("/kdb_sybase_XXXXXX.conf"));
0136     confFile.open();
0137 
0138     QTextStream out(&confFile);
0139 
0140     // write global portion
0141     out << "[global]" << "\n";
0142     out << " text size = " << 64512 << "\n" ; // Copied from default freetds.conf. is there a more reasonable number?
0143 
0144 
0145     // write server portion
0146     out << '[' << data.serverName << ']' << "\n";
0147     out << " host = " << hostName << "\n";
0148 
0149     if (data.port == 0)
0150         out << " port = " << 5000 << "\n"; // default port to be used
0151     else
0152         out << " port = " << data.port << "\n";
0153 
0154     out << " tds version = " << 5.0 << "\n";
0155 
0156     // set the file to be read as confFile
0157     dbsetifile(confFile.fileName().toLatin1().data());
0158 
0159     // set Login parameters
0160     QByteArray pwd(data.password.isNull() ? QByteArray() : data.password.toLatin1());
0161 
0162     DBSETLUSER(login, data.userName.toLatin1());
0163     DBSETLPWD(login, pwd);
0164     DBSETLAPP(login, qApp->applicationName().toLatin1());
0165 
0166     // make the connection
0167     // Host name assumed to be same as servername
0168     // where are ports specified ? ( in the interfaces file ? )
0169 
0170     dbProcess = dbopen(login, data.serverName.toLatin1().data());
0171 
0172     dbloginfree(login);
0173 
0174     // Set/ Unset quoted identifier ? ?
0175 
0176     if (dbProcess) {
0177         // add to map
0178         SybaseConnectionInternal::dbProcessConnectionMap[dbProcess] = this;
0179 
0180         // set buffering to be true
0181         // what's a reasonable value of no. of rows to be kept in buffer ?
0182         // dbsetopt( dbProcess, DBBUFFER, "500", -1 );
0183 
0184         // set quoted identifier to be true
0185         dbsetopt(dbProcess, DBQUOTEDIDENT, "1", -1);
0186 
0187         return true;
0188     }
0189 
0190     storeResult();
0191 
0192     //dbexit();
0193 // setError(ERR_DB_SPECIFIC,err);
0194     return false;
0195 }
0196 
0197 bool SybaseConnectionInternal::db_disconnect()
0198 {
0199     dbclose(dbProcess);
0200     dbProcess = 0;
0201     return true;
0202 }
0203 
0204 bool SybaseConnectionInternal::useDatabase(const QString &dbName)
0205 {
0206     if (dbuse(dbProcess, dbName.toLatin1().data()) == SUCCEED) {
0207         return true;
0208     }
0209 
0210     return false;
0211 }
0212 
0213 bool SybaseConnectionInternal::executeSql(const KDbEscapedString& sql)
0214 {
0215     // remove queries in buffer if any. flush existing results if any
0216     dbcancel(dbProcess);
0217     // put query in command bufffer
0218     dbcmd(dbProcess, sql.constData());
0219     if (dbsqlexec(dbProcess) == SUCCEED) {
0220         while (dbresults(dbProcess) != NO_MORE_RESULTS) {
0221             /* nop */
0222         }
0223         return true;
0224     }
0225 
0226     // Error.handling
0227 
0228     storeResult();
0229     return false;
0230 }
0231 
0232 QString SybaseConnectionInternal::escapeIdentifier(const QString& str) const
0233 {
0234     return QString(str).replace("'", "''");
0235 }
0236 
0237 //--------------------------------------
0238 
0239 SybaseCursorData::SybaseCursorData(KDbConnection* connection)
0240         : SybaseConnectionInternal(connection)
0241         , numRows(0)
0242 {
0243     sybase_owned = false;
0244 }
0245 
0246 SybaseCursorData::~SybaseCursorData()
0247 {
0248 }