在 debian 上使用 qt 訪問 oracle 資料庫
技術標籤:SQLServer/mySQL/Oracle資料庫技術
原文地址::https://ouonline.net/connecting-to-oracle-with-qt-on-debian
之前的一個使用 oracle 的專案自從我把資料庫裝好之後就沒有下文了,最近迎來了另一個也需要使用 oracle 的專案。由於 oracle 不是開源的,為了能在 Linux 下使用 qt 訪問,只好自己編譯對應的驅動。在網上找了一堆資料,又折騰了好幾天,終於在今天晚上成功了,在這裡記錄一下。
先說一下環境:debian 6.0,qt sdk 4.8.1,oracle 11gR2。本文主要記錄的是怎樣編譯驅動和怎樣連線,關於 oracle 資料庫伺服器端安裝中的一些問題可以參考之前的一篇
準備工作
下載 qt sdk。因為編譯的時候 qt 工具鏈和原始碼要保持一致,而 debian 6 源裡的 qt 版本是 4.6.3,官網上已經找不到對應的原始碼包了,所以下載 sdk 安裝(sdk 包含工具鏈和對應版本的原始碼),安裝的時候要注意把安裝 source code 的選項勾上。這裡使用 QTDIR 表示 qt sdk 的安裝目錄(這個環境變數不是必須的,只是為了描述方便,因此在下面出現這個目錄的時候把它替換成實際的安裝目錄)。
安裝和 oracle 服務端對應版本的 oracle instant client(runtime 部分),安裝目錄為 ORACLE_CLIENT_HOME(這個環境變數也不是必須的,只是為了描述方便)。這個東東主要包含編譯驅動所需的標頭檔案和動態連結庫。安裝過程就不詳細說了,出現的各種錯誤提示都被我跳過了。選擇安裝 InstantClient 能找到後面執行需要的 .so。
安裝了 qt sdk 和 instant client 的機器以下簡稱 client,裝有 oracle 資料庫的機器為 server(當然這兩個可以是同一臺機器)。
編譯 QOCI 驅動
編譯工作在 client 上進行。
由於許可證的限制,qt 的開源版本並沒有帶編譯好的 oracle 驅動,但是原始碼中有編譯的程式碼,位於(把其中的版本號“4.8.1”替換成實際使用的版本號):
$QTDIR/QtSources/4.8.1/src/plugins/sqldrivers/oci
這個目錄下的 main.cpp 和 oci.pro 就是我們需要的程式碼。從 server 上的 $ORACLE_HOME/lib 中找到 libclntsh.so,libclntsh.so.10.1 和 libclntsh.so.11.1(其實這三個檔案是同一個東西,前兩個是連結到第三個的符號連結),把它們複製到這個目錄,然後在 oci.pro 中新增標頭檔案和庫的位置(最後 3 行):
TARGET = qsqloci
SOURCES = main.cpp
include(../../../sql/drivers/oci/qsql_oci.pri)
include(../qsqldriverbase.pri)
INCLUDEPATH+=$ORACLE_CLIENT_HOME/rdbms/public
INCLUDEPATH+=$QTDIR/QtSources/4.8.1/include
LIBS+= -L. -lclntsh
然後使用下面的命令編譯:
$QTDIR/Desktop/Qt/4.8.1/gcc/bin/qmake oci.pro
make
如果編譯成功會生成一個 libqsqloci.so,這個就是我們需要的驅動。
連線資料庫
測試是在 client 上進行的。測試程式放在 $ORACLE_TEST 目錄。
把上面生成的 libqsqloci.so 放到下面的目錄中:
$QTDIR/Desktop/Qt/4.8.1/gcc/plugins/sqldrivers
然後編寫測試程式(把其中的 dbhost,dbusr 和 dbpasswd 替換成實際的名字):
#include <QSqlDatabase>
#include <QSqlError>
#include <QDebug>
#include <QStringList>
int main(void)
{
QSqlDatabase db;
QStringList drivers = QSqlDatabase::drivers();
foreach (QString driver, drivers)
qDebug() << driver;
db = QSqlDatabase::addDatabase("QOCI");
db.setDatabaseName("orcl"); /* default */
db.setPort(1521);
db.setHostName("<dbhost>");
db.setUserName("<dbusr>");
db.setPassword("<dbpasswd>");
if (db.open())
qDebug() << "connect ok";
else
qDebug() << db.lastError().text();
return 0;
}
關鍵時刻到了。先看編譯程式的 Makefile:
QTPATH := $(QTDIR)/Desktop/Qt/4.8.1/gcc
INCLUDE := -I$(QTPATH)/include -I$(QTPATH)/include/QtCore -I$(QTPATH)/include/QtSql
LIBS := -L$(QTPATH)/lib -lQtCore -lQtSql -L. -lclntsh
TARGET := oracletest
$(TARGET): oracletest.o
g++ -o [email protected] $^ $(LIBS)
.cpp.o:
g++ -c $< $(INCLUDE)
clean:
rm -f *.o $(TARGET)
然後設定環境變數:
export ORACLE_HOME=$ORACLE_CLIENT_HOME
export LD_LIBRARY_PATH=$QTDIR/Desktop/Qt/4.8.1/gcc/lib:$ORACLE_HOME/lib:$LD_LIBRARY_PATH
雖然這是在 client 端,但是還是要設定 ORACLE_HOME(沒錯,client 端的環境變數也叫這個,如果不設定會出現“QOCIDriver: unable to create environment”的錯誤提示,解決這個問題花了我一下午的時間)。
(2012.09.05 補充)我安裝的時候使用的是 oracle client 的完整安裝包,安裝介面上包含 4 個選項:InstantClient,Administrator,Runtime 和 Custom。如果選了 InstantClient 能找到上面提到的幾個 .so,但是執行的時候同樣會提示錯誤“QOCIDriver: unable to create environment”,還要重新裝 Runtime,並且在設定環境變數的時候把 ORACLE_HOME 設為 Runtime 部分的安裝目錄而不是 InstantClient 的目錄。
然後編譯執行:
make && ./oracletest
如果一切順利,最後看到的輸出類似於下面這樣:
"QSQLITE"
"QOCI8"
"QOCI"
connect ok
後記
寫這篇筆記也就用了 1 小時多點,但是這幾天的經歷和心情卻是很痛苦,其中走了多少彎路浪費了多少時間。作為一個使用過 LFS 和 FVWM 的使用者,這兩次折騰讓我最不能明白的是,像 oracle 這種反社會反人類反科學的軟體怎麼會一直存在並活得好好的。
參考資料
[1]QOCI for the Oracle Call Interface (OCI)
[2]QOCI編譯筆記
Comment (1)
-
lei
Oracle和微軟策略類似,用準盜版方式培育市場(軟體安裝media可以從官網下載,並且沒有多少限制,只是沒有補丁,對行業標杆使用者進行超低價重點培育等),形成了廣泛的開發和使用人員隊伍,並形成技術輿論影響,一旦有了大批靠他吃飯的,就成功了。
BTW,目前我也靠他吃飯。