Intereting Posts
Согласование шаблонов и обработка текста для списков файлов песен Как изменить тему рабочего стола в CentOS? заменяя содержимое одного файла другим Есть ли способ сделать минимальную установку CentOS без LVM / ext4? Arch Linux Kde – уменьшить количество панельных приложений Наследовать перенаправления IO из сценария в другой Может кто-нибудь объяснить, что делает этот chown на самом деле? Как заставить сервер X создавать определенные ключи и состояние? mutt после запроса пароля, используемого как для imap, так и для smtp Почему мой единственный экземпляр VLC имеет много процессов? Оптимальные корневые флагов для rootfs для файловой системы ext4, работающей на USB-накопителе Стресс-тестирование SD-карт с использованием linux Блок автоматической установки EncFS Как я могу зарегистрировать динамически названную переменную в задаче Ansible? Подключение fetchmail (или другого MRA) к Exchange

SQLDriverConnect (из unix-odbc) кэширует данные DSN? Если да, то как я могу его очистить / очистить?

При использовании библиотек UNIX-ODBC с сайта unixodbc у меня возникла проблема с SQLDriverConnect api. Если я попытаюсь дважды подключиться к моей базе данных, сначала с неправильными данными DSN (данные источника данных, помещенными в /etc/odbc.ini целом) и второй с правильными данными, вторая попытка подключения также не выполняется. Причиной неудачи является то, что SQLDriverConnect похоже, использует неверные данные, поданные в него в первом запуске.

После очистки сети за любые упоминания о ее кешировании данных, похоже, никто другой не сталкивался с этой конкретной проблемой (или мой поиск был неадекватным).

Вариант использования для меня заключается в том, что я предоставляю графический интерфейс, в котором пользователь может вручную заполнить форму всеми параметрами, а затем нажать кнопку «Проверить соединение». Это будет записывать (или перезаписывать) данные в файл /etc/odbc.ini , а затем пытаться подключиться к базе данных с помощью unixodbc apis. Если тест завершится успешно, строка соединения, возвращаемая из SQLDriverConnect будет заполнена в графическом интерфейсе. Если это не удается, GUI отобразит сбой и позволит пользователю редактировать данные в форме и снова нажать кнопку «Проверить соединение».

Проблема. Если пользователь вводит неверные данные (например, номер порта), тест терпит неудачу, и пользователь исправляет данные. Когда пользователь пытается проверить соединение, он должен пройти, так как все данные верны и также правильно odbc.ini файле odbc.ini . Безумно, это не удается для второго повторного тестирования. Однако иногда третий или четвертый повторный опрос он может подключиться должным образом.

Обратите внимание, что пересоединения в идеале должны быть в одном прогоне программы, поскольку повторный запуск программы, похоже, не создает проблемы. Это важно для меня, когда тесты будут запускаться с серверной стороны и не будут иметь роскошь перезапуска.


Сведения о системе

Ниже приведены детали систем, используемых для разработки и выполнения выборки позже:

 Developement Machine CentOS release 6.1 (Final) 2.6.32-131.0.15.el6.i686 {32bit machine} Deployment Machine (CentOS) Linux release 6.6 (Final) 2.6.32-573.el6.x86_64 {64bit machine} unixODBC 2.2.14 /usr/lib/psqlodbcw.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, stripped 

, ,

Образец кода

Создайте код с помощью libodbc, как показано ниже:

g ++ -g -o code code.cpp -lodbc

Обратите внимание, что вам может потребоваться убедиться, что включены файлы и библиотеки.

 #include "../boost_1_52_0/boost/property_tree/ptree.hpp" #include "../boost_1_52_0/boost/property_tree/ini_parser.hpp" #include <iostream> #include <string> #include <vector> #include <utility> #include <unistd.h> #include "../unixODBC-2.3.4/include/sql.h" #include "../unixODBC-2.3.4/include/sqlext.h" #include "../unixODBC-2.3.4/include/odbcinst.h" using boost::property_tree::ptree; using namespace std; void PopulateINI(const string& iniName, vector<pair<string, string> >& data); bool TestConnection(const string& connStringIn, string& connStringOut); static void extract_error(char *fn, SQLHANDLE handle, SQLSMALLINT type); void PrintIniFile(const string& iniName, const string& sDSN); int main(int argc, char* argv[]) { if (argc != 2) { cout << "Enter the choice of\n\t1 : Full run:- \n\t\t\tpopulate incorrect data\n\t\t\tattempt to connect\n\t\t\tpopulate CORRECT data\n\t\t\twait 15 secs\n\t\t\tattempt to connect\n\t2 : attempt to connect with existing ini data" << endl; return 0; } int iCh = atoi(argv[1]); if(iCh != 1 && iCh != 2) { cout << "Invalid choice !!\nAcceptable values are - '1' OR '2' only" << endl; return 0; } string sDSN = "PostgresTest01"; string sConnStrIn, sConnStrOut; sConnStrIn.append("DSN=").append(sDSN.c_str()).append(1, ';'); string iniName = "/etc/odbc.ini"; if (iCh == 1) { //Incorrect DSN data vector<pair<string, string> > vData; vData.push_back(make_pair(sDSN + ".Description", "Description")); vData.push_back(make_pair(sDSN + ".Driver", "PostgreSQL")); vData.push_back(make_pair(sDSN + ".Database", "dvdrental")); vData.push_back(make_pair(sDSN + ".Servername", "192.168.45.217")); vData.push_back(make_pair(sDSN + ".Port", "1234")); //INCORRECT PORT NUMBER; '1234' instead of '5432' vData.push_back(make_pair(sDSN + ".UserName", "postgres")); vData.push_back(make_pair(sDSN + ".Password", "postgres")); vData.push_back(make_pair(sDSN + ".Trace", "Off")); vData.push_back(make_pair(sDSN + ".TraceFile", "stderr")); vData.push_back(make_pair(sDSN + ".Protocol", "7.0")); vData.push_back(make_pair(sDSN + ".ReadOnly", "No")); vData.push_back(make_pair(sDSN + ".RowVersioning", "No")); vData.push_back(make_pair(sDSN + ".ShowSystemTables", "No")); vData.push_back(make_pair(sDSN + ".ShowOidColumn", "No")); vData.push_back(make_pair(sDSN + ".FakeOidIndex", "No")); vData.push_back(make_pair(sDSN + ".ConnSettings", "")); //Populate ini with Incorrect data PopulateINI(iniName, vData); sleep(5); //Just so I can see the ini file changing //First run - Call SQLDriverConnect PrintIniFile(iniName, sDSN); sConnStrOut.clear(); if(TestConnection(sConnStrIn, sConnStrOut)) { cout << "Test connection succeeded.\nConnection String is [" << sConnStrOut << "]" << endl; } else { cout << "Test connection failed for sConnStrIn[" << sConnStrIn << "]" << endl; } cout << "\n\n====================================================================" << endl; cout << "Updating ini file with correct data..." << endl; vData[4].second = "5432"; //CORRECT PORT NUMBER PopulateINI(iniName, vData); //WRITE TO INI FILE cout << "\n\nWaiting for 15 secs" << endl; sleep(15); //15, so that I could manually change the odbc.ini, as I had some suspicions about ptree, read_ini() & write_ini() cout << "\n\n====================================================================" << endl; } //Second run - Call SQLDriverConnect PrintIniFile(iniName, sDSN); sConnStrOut.clear(); if(TestConnection(sConnStrIn, sConnStrOut)) { cout << "Test connection succeeded.\nConnection String is [" << sConnStrOut << "]" << endl;; } else { cout << "Test connection failed for sConnStrIn[" << sConnStrIn << "]" << endl; } return 0; } void PrintVector(const string& label, vector<pair<string, string> >& data) { cout << "\n\n " << label << "\n" << endl; for(vector<pair<string, string> >::iterator it = data.begin(); it != data.end(); ++it) { cout << "\t\t" << it->first << " : " << it->second << endl; } cout << "\n===================================================" << endl; } void PopulateINI(const string& iniName, vector<pair<string, string> >& data) { ptree pt; read_ini(iniName.c_str(), pt); for(vector<pair<string, string> >::iterator it = data.begin(); it != data.end(); ++it) { pt.put(it->first.c_str(), it->second.c_str()); } write_ini(iniName.c_str(), pt); } bool TestConnection(const string& connStringIn, string& connStringOut) { bool fRC = false; SQLRETURN retcode; SQLHENV env=NULL; SQLHDBC dbc=NULL; SQLSMALLINT siOutConnStrLen; connStringOut.resize(2048); SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc); retcode = SQLDriverConnect(dbc, NULL, (SQLCHAR*)connStringIn.c_str(), SQL_NTS, (SQLCHAR*)&connStringOut.at(0), 2048, &siOutConnStrLen, SQL_DRIVER_NOPROMPT); if(SQL_SUCCEEDED(retcode)) { connStringOut.resize(siOutConnStrLen); fRC = true; if(retcode == SQL_SUCCESS_WITH_INFO) { cout << "Driver reported the following diagnostics:" << endl; extract_error("SQLDriverConnect", dbc, SQL_HANDLE_DBC); } SQLDisconnect(dbc); } else { cout << "Failed to connect:" << endl; extract_error("SQLDriverConnect", dbc, SQL_HANDLE_DBC); } SQLFreeHandle(SQL_HANDLE_DBC, dbc); SQLFreeHandle(SQL_HANDLE_ENV, env); return fRC; } void extract_error(char *fn, SQLHANDLE handle, SQLSMALLINT type) { SQLINTEGER i = 0; SQLINTEGER native; SQLCHAR state[ 7 ]; SQLCHAR text[256]; SQLSMALLINT len; SQLRETURN ret; fprintf(stderr, "\nThe driver reported the following diagnostics whilst running %s\n\n", fn); do { ret = SQLGetDiagRec(type, handle, ++i, state, &native, text, sizeof(text), &len ); if (SQL_SUCCEEDED(ret)) printf("%s:%ld:%ld:%s\n", state, i, native, text); } while( ret == SQL_SUCCESS ); } void PrintIniFile(const string& iniName, const string& sDSN) { ptree pt; read_ini(iniName.c_str(), pt); cout << "\n\n[" << sDSN << "]" << endl; cout << "Description : " << pt.get<string>((sDSN + "." + "Description").c_str()) <<endl; cout << "Driver : " << pt.get<string>((sDSN + "." + "Driver").c_str()) <<endl; cout << "Database : " << pt.get<string>((sDSN + "." + "Database").c_str()) <<endl; cout << "Servername : " << pt.get<string>((sDSN + "." + "Servername").c_str()) <<endl; cout << "Port : " << pt.get<string>((sDSN + "." + "Port").c_str()) <<endl; cout << "UserName : " << pt.get<string>((sDSN + "." + "UserName").c_str()) <<endl; cout << "Password : " << pt.get<string>((sDSN + "." + "Password").c_str()) <<endl; cout << "Trace : " << pt.get<string>((sDSN + "." + "Trace").c_str()) <<endl; cout << "TraceFile : " << pt.get<string>((sDSN + "." + "TraceFile").c_str()) <<endl; cout << "Protocol : " << pt.get<string>((sDSN + "." + "Protocol").c_str()) <<endl; cout << "ReadOnly : " << pt.get<string>((sDSN + "." + "ReadOnly").c_str()) <<endl; cout << "RowVersioning : " << pt.get<string>((sDSN + "." + "RowVersioning").c_str()) <<endl; cout << "ShowSystemTables : " << pt.get<string>((sDSN + "." + "ShowSystemTables").c_str()) <<endl; cout << "ShowOidColumn : " << pt.get<string>((sDSN + "." + "ShowOidColumn").c_str()) <<endl; cout << "FakeOidIndex : " << pt.get<string>((sDSN + "." + "FakeOidIndex").c_str()) <<endl; cout << "ConnSettings : " << pt.get<string>((sDSN + "." + "ConnSettings").c_str()) <<endl; cout << "\n\n" << endl; } 

, ,

выполнение

Программа принимает один аргумент: «1» или «2».

 1 : Full run:- populate incorrect data attempt to connect populate CORRECT data wait 15 secs attempt to connect 2 : attempt to connect with existing ini data 

например

./code 1

ИЛИ

./code 2

Выходы

Для полного запуска ./code 1 ниже представлен результат. Обратите внимание, что перед второй попыткой подключения odbc.ini был изменен и прочитан для отображения правильного «номера порта».

 [PostgresTest01] Description : Description Driver : PostgreSQL Database : dvdrental Servername : 192.168.45.217 Port : 1234 UserName : postgres Password : postgres Trace : Off TraceFile : stderr Protocol : 7.0 ReadOnly : No RowVersioning : No ShowSystemTables : No ShowOidColumn : No FakeOidIndex : No ConnSettings : Failed to connect: The driver reported the following diagnostics whilst running SQLDriverConnect 08001:1:101:[unixODBC]Could not connect to the server; Connection refused [192.168.45.217:1234] Test connection failed for sConnStrIn[DSN=PostgresTest01;] ==================================================================== Updating ini file with correct data... Waiting for 15 secs ==================================================================== [PostgresTest01] Description : Description Driver : PostgreSQL Database : dvdrental Servername : 192.168.45.217 Port : 5432 UserName : postgres Password : postgres Trace : Off TraceFile : stderr Protocol : 7.0 ReadOnly : No RowVersioning : No ShowSystemTables : No ShowOidColumn : No FakeOidIndex : No ConnSettings : Failed to connect: The driver reported the following diagnostics whilst running SQLDriverConnect 08001:1:101:[unixODBC]Could not connect to the server; Connection refused [192.168.45.217:1234] Test connection failed for sConnStrIn[DSN=PostgresTest01;] 

, , Обратите внимание, что во второй попытке, хотя ini отражает правильные данные, напечатанные за 15 секунд до попытки подключения, сообщение об ошибке показывает, что соединение отказывается от порта «1234».

Соединение отклонено [192.168.45.217:1234]. ,


, ,

Для быстрого запуска ./code 2 , сразу после первого запуска, после которого ini содержит правильные данные, ниже приведен вывод. Ему удается подключиться.

 [PostgresTest01] Description : Description Driver : PostgreSQL Database : dvdrental Servername : 192.168.45.217 Port : 5432 UserName : postgres Password : postgres Trace : Off TraceFile : stderr Protocol : 7.0 ReadOnly : No RowVersioning : No ShowSystemTables : No ShowOidColumn : No FakeOidIndex : No ConnSettings : Test connection succeeded. Connection String is [DSN=PostgresTest01;DATABASE=dvdrental;SERVER=192.168.45.217;PORT=5432;UID=postgres;PWD=postgres;SSLmode=disable;ReadOnly=No;Protocol=7.0;FakeOidIndex=No;ShowOidColumn=No;RowVersioning=No;ShowSystemTables=No;ConnSettings=;Fetch=100;Socket=4096;UnknownSizes=0;MaxVarcharSize=255;MaxLongVarcharSize=8190;Debug=0;CommLog=0;Optimizer=0;Ksqo=1;UseDeclareFetch=0;TextAsLongVarchar=1;UnknownsAsLongVarchar=0;BoolsAsChar=1;Parse=0;CancelAsFreeStmt=0;ExtraSysTablePrefixes=dd_;;LFConversion=0;UpdatableCursors=1;DisallowPremature=0;TrueIsMinus1=0;BI=0;ByteaAsLongVarBinary=0;UseServerSidePrepare=0;LowerCaseIdentifier=0;] 

, ,

Вопросов

Повторяя вопросы здесь.

  1. Почему ./code 1 приводит к сбою обоих тестов соединения?
  2. Является ли SQLDriverConnect каким-то образом кэшированием данных, что способствует правильному освобождению дескрипторов между попытками подключения?
  3. Как можно очистить этот предполагаемый кеш, чтобы вторая попытка была успешной?
  4. Если это действительно ошибка, есть ли способ обхода решения для достижения желаемого результата в последующих тестах в рамках одного и того же запуска программы ( помните, что тесты должны запускаться с сервера, который не может перезагружаться )?

, ,

Я бы посмотрел на попытку последней версии диспетчера драйверов, 2.2.14 – с 2008 года. Это может не исправить проблему с попыткой последующей сборки, но, конечно, исправления добавлены в код кеширования.

Кроме того, при создании 2.3.x я бы добавил –enable-inicaching = no для configure. Это может быть причиной проблемы, которую вы видите.