19 Star 39 Fork 46

openGauss / openGauss-connector-odbc

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
drvconn.c 14.32 KB
一键复制 编辑 原始数据 按行查看 历史
zhangxubo 提交于 2022-03-11 17:10 . add 3.0.0 patch file
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
/*-------
Module: drvconn.c
*
* Description: This module contains only routines related to
* implementing SQLDriverConnect.
*
* Classes: n/a
*
* API functions: SQLDriverConnect
*
* Comments: See "readme.txt" for copyright and license information.
*-------
*/
#include "psqlodbc.h"
#include <stdio.h>
#include <stdlib.h>
#include "connection.h"
#include "misc.h"
#ifndef WIN32
#include <sys/types.h>
#include <sys/socket.h>
#else
#include <winsock2.h>
#endif
#include <string.h>
#ifdef WIN32
#include <windowsx.h>
#include "resource.h"
#endif
#include "pgapifunc.h"
#include "dlg_specific.h"
#define FORCE_PASSWORD_DISPLAY
#define NULL_IF_NULL(a) (a ? a : "(NULL)")
#ifndef FORCE_PASSWORD_DISPLAY
static char * hide_password(const char *str)
{
char *outstr, *pwdp;
if (!str) return NULL;
outstr = strdup(str);
if (!outstr) return NULL;
if (pwdp = strstr(outstr, "PWD="), !pwdp)
pwdp = strstr(outstr, "pwd=");
if (pwdp)
{
char *p;
for (p=pwdp + 4; *p && *p != ';'; p++)
*p = 'x';
}
return outstr;
}
#endif
/* prototypes */
static BOOL dconn_get_DSN_or_Driver(const char *connect_string, ConnInfo *ci);
static BOOL dconn_get_connect_attributes(const char *connect_string, ConnInfo *ci);
#ifdef WIN32
LRESULT CALLBACK dconn_FDriverConnectProc(HWND hdlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
RETCODE dconn_DoDialog(HWND hwnd, ConnInfo *ci);
extern HINSTANCE s_hModule; /* Saved module handle. */
#endif
#define PASSWORD_IS_REQUIRED 1
static int
paramRequired(const ConnInfo *ci, int reqs)
{
int required = 0;
const char *pw = SAFE_NAME(ci->password);
/* Password is not necessarily a required parameter. */
if ((reqs & PASSWORD_IS_REQUIRED) != 0)
if ('\0' == pw[0])
required |= PASSWORD_IS_REQUIRED;
return required;
}
RETCODE SQL_API
PGAPI_DriverConnect(HDBC hdbc,
HWND hwnd,
const SQLCHAR * szConnStrIn,
SQLSMALLINT cbConnStrIn,
SQLCHAR * szConnStrOut,
SQLSMALLINT cbConnStrOutMax,
SQLSMALLINT * pcbConnStrOut,
SQLUSMALLINT fDriverCompletion)
{
CSTR func = "PGAPI_DriverConnect";
ConnectionClass *conn = (ConnectionClass *) hdbc;
ConnInfo *ci;
#ifdef WIN32
RETCODE dialog_result;
BOOL didUI = FALSE;
#endif
const char *lackMessage = NULL;
RETCODE result;
char *connStrIn = NULL;
char connStrOut[MAX_CONNECT_STRING];
int retval;
char salt[5];
ssize_t len = 0;
SQLSMALLINT lenStrout;
int reqs = 0;
MYLOG(0, "entering...\n");
if (!conn)
{
CC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
}
connStrIn = make_string(szConnStrIn, cbConnStrIn, NULL, 0);
/* CodeDEX with CID=11878 */
if (NULL == connStrIn)
{
CC_set_error(conn, CONN_NO_MEMORY_ERROR, "Out of memory while making_string for connStrIn", func);
return SQL_ERROR;
}
#ifdef FORCE_PASSWORD_DISPLAY
MYLOG(0, "**** fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, connStrIn);
#else
if (get_mylog())
{
char *hide_str = hide_password(connStrIn);
MYLOG(0, "**** fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, NULL_IF_NULL(hide_str));
if (hide_str)
free(hide_str);
}
#endif /* FORCE_PASSWORD_DISPLAY */
ci = &(conn->connInfo);
/* First parse the connect string and get the name of DSN or Driver */
if (!dconn_get_DSN_or_Driver(connStrIn, ci))
{
CC_set_error(conn, CONN_OPENDB_ERROR, "Connection string parse error", func);
return SQL_ERROR;
}
/*
* If the ConnInfo in the hdbc is missing anything, this function will
* fill them in from the registry (assuming of course there is a DSN
* given -- if not, it does nothing!)
*/
getDSNinfo(ci, NULL);
/* Parse the connect string and fill in conninfo for this hdbc. */
if (!dconn_get_connect_attributes(connStrIn, ci))
{
CC_set_error(conn, CONN_OPENDB_ERROR, "Connection string parse error", func);
return SQL_ERROR;
}
logs_on_off(1, ci->drivers.debug, ci->drivers.commlog);
if (connStrIn)
{
free(connStrIn);
connStrIn = NULL;
}
/* initialize pg_version */
CC_initialize_pg_version(conn);
memset(salt, 0, sizeof(salt));
#ifdef WIN32
dialog:
#endif
MYLOG(DETAIL_LOG_LEVEL, "DriverCompletion=%d\n", fDriverCompletion);
switch (fDriverCompletion)
{
#ifdef WIN32
case SQL_DRIVER_PROMPT:
if (NULL == hwnd)
break;
dialog_result = dconn_DoDialog(hwnd, ci);
didUI = TRUE;
if (dialog_result != SQL_SUCCESS)
return dialog_result;
break;
case SQL_DRIVER_COMPLETE_REQUIRED:
/* Fall through */
case SQL_DRIVER_COMPLETE:
if (NULL == hwnd)
break;
if (paramRequired(ci, reqs))
{
dialog_result = dconn_DoDialog(hwnd, ci);
didUI = TRUE;
if (dialog_result != SQL_SUCCESS)
return dialog_result;
}
break;
#else
case SQL_DRIVER_PROMPT:
case SQL_DRIVER_COMPLETE:
case SQL_DRIVER_COMPLETE_REQUIRED:
#endif
case SQL_DRIVER_NOPROMPT:
break;
}
/*
* Password is not a required parameter unless authentication asks for
* it. For now, I think it's better to just let the application ask
* over and over until a password is entered (the user can always hit
* Cancel to get out)
*/
if (paramRequired(ci, reqs))
{
if (!lackMessage)
lackMessage = "Please supply password";
CC_set_error(conn, CONN_OPENDB_ERROR, lackMessage, func);
return SQL_ERROR;
}
reqs = 0;
MYLOG(DETAIL_LOG_LEVEL, "before CC_connect\n");
/* do the actual connect */
retval = CC_connect(conn, salt);
if (retval < 0)
{ /* need a password */
if (fDriverCompletion == SQL_DRIVER_NOPROMPT)
{
CC_log_error(func, "Need password but Driver_NoPrompt", conn);
return SQL_ERROR; /* need a password but not allowed to
* prompt so error */
}
else
{
#ifdef WIN32
if (ci->password_required)
reqs |= PASSWORD_IS_REQUIRED;
if (hwnd && paramRequired(ci, reqs))
goto dialog;
#endif /* WIN32 */
/* Prompting for missing options is only supported on Windows. */
return SQL_ERROR;
}
}
else if (retval == 0)
{
/* error msg filled in above */
CC_log_error(func, "Error from CC_Connect", conn);
return SQL_ERROR;
}
/*
* Create the Output Connection String
*/
result = (1 == retval ? SQL_SUCCESS : SQL_SUCCESS_WITH_INFO);
lenStrout = cbConnStrOutMax;
if (conn->ms_jet && lenStrout > 255)
lenStrout = 255;
makeConnectString(connStrOut, ci, lenStrout);
len = strlen(connStrOut);
if (szConnStrOut)
{
/*
* Return the completed string to the caller. The correct method
* is to only construct the connect string if a dialog was put up,
* otherwise, it should just copy the connection input string to
* the output. However, it seems ok to just always construct an
* output string. There are possible bad side effects on working
* applications (Access) by implementing the correct behavior,
* anyway.
*/
strncpy((char *) szConnStrOut, connStrOut, cbConnStrOutMax);
if (len >= cbConnStrOutMax)
{
int clen;
for (clen = cbConnStrOutMax - 1; clen >= 0 && szConnStrOut[clen] != ';'; clen--)
szConnStrOut[clen] = '\0';
result = SQL_SUCCESS_WITH_INFO;
CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the ConnStrOut.", func);
}
}
if (pcbConnStrOut)
*pcbConnStrOut = (SQLSMALLINT) len;
#ifdef FORCE_PASSWORD_DISPLAY
if (cbConnStrOutMax > 0)
{
MYLOG(0, "szConnStrOut = '%s' len=" FORMAT_SSIZE_T ",%d\n", NULL_IF_NULL((char *) szConnStrOut), len, cbConnStrOutMax);
}
#else
if (get_mylog())
{
char *hide_str = NULL;
if (cbConnStrOutMax > 0)
hide_str = hide_password(szConnStrOut);
MYLOG(0, "szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL(hide_str), len, cbConnStrOutMax);
if (hide_str)
free(hide_str);
}
#endif /* FORCE_PASSWORD_DISPLAY */
MYLOG(0, "leaving %d\n", result);
return result;
}
#ifdef WIN32
RETCODE
dconn_DoDialog(HWND hwnd, ConnInfo *ci)
{
LRESULT dialog_result;
MYLOG(0, "entering ci = %p\n", ci);
if (hwnd)
{
dialog_result = DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_CONFIG),
hwnd, dconn_FDriverConnectProc, (LPARAM) ci);
if (-1 == dialog_result)
{
int errc = GetLastError();
MYLOG(0, " LastError=%d\n", errc);
}
if (!dialog_result || (dialog_result == -1))
return SQL_NO_DATA_FOUND;
else
return SQL_SUCCESS;
}
MYLOG(0, " No window specified\n");
return SQL_ERROR;
}
LRESULT CALLBACK
dconn_FDriverConnectProc(
HWND hdlg,
UINT wMsg,
WPARAM wParam,
LPARAM lParam)
{
ConnInfo *ci;
char strbuf[64];
switch (wMsg)
{
case WM_INITDIALOG:
ci = (ConnInfo *) lParam;
/* Change the caption for the setup dialog */
SetWindowText(hdlg, "PostgreSQL Connection");
LoadString(s_hModule, IDS_ADVANCE_CONNECTION, strbuf, sizeof(strbuf));
SetWindowText(GetDlgItem(hdlg, IDC_DATASOURCE), strbuf);
/* Hide the DSN and description fields */
ShowWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), SW_HIDE);
ShowWindow(GetDlgItem(hdlg, IDC_DSNAME), SW_HIDE);
ShowWindow(GetDlgItem(hdlg, IDC_DESCTEXT), SW_HIDE);
ShowWindow(GetDlgItem(hdlg, IDC_DESC), SW_HIDE);
ShowWindow(GetDlgItem(hdlg, IDC_DRIVER), SW_HIDE);
ShowWindow(GetDlgItem(hdlg, IDC_TEST), SW_HIDE);
ShowWindow(GetDlgItem(hdlg, IDC_MANAGEDSN), SW_HIDE);
if ('\0' != ci->server[0])
EnableWindow(GetDlgItem(hdlg, IDC_SERVER), FALSE);
if ('\0' != ci->port[0])
EnableWindow(GetDlgItem(hdlg, IDC_PORT), FALSE);
SetWindowLongPtr(hdlg, DWLP_USER, lParam); /* Save the ConnInfo for the "OK" */
SetDlgStuff(hdlg, ci);
if (ci->password_required)
{
HWND notu = GetDlgItem(hdlg, IDC_NOTICE_USER);
SetFocus(GetDlgItem(hdlg, IDC_PASSWORD));
SetWindowText(notu, " Supply password ");
ShowWindow(notu, SW_SHOW);
SendMessage(notu, WM_CTLCOLOR, 0, 0);
}
else if (ci->database[0] == '\0')
; /* default focus */
else if (ci->server[0] == '\0')
SetFocus(GetDlgItem(hdlg, IDC_SERVER));
else if (ci->port[0] == '\0')
SetFocus(GetDlgItem(hdlg, IDC_PORT));
else if (ci->username[0] == '\0')
SetFocus(GetDlgItem(hdlg, IDC_USER));
else if (ci->autobalance == 0)
SetFocus(GetDlgItem(hdlg, IDC_AB));
else if (ci->refreshcnlisttime == 0)
SetFocus(GetDlgItem(hdlg, IDC_RT));
else if (ci->priority == 0)
SetFocus(GetDlgItem(hdlg, IDC_PR));
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDOK:
ci = (ConnInfo *) GetWindowLongPtr(hdlg, DWLP_USER);
GetDlgStuff(hdlg, ci);
case IDCANCEL:
EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
return TRUE;
case IDC_DATASOURCE:
ci = (ConnInfo *) GetWindowLongPtr(hdlg, DWLP_USER);
DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DRV),
hdlg, ds_options1Proc, (LPARAM) ci);
break;
}
break;
case WM_CTLCOLORSTATIC:
if (lParam == (LPARAM)GetDlgItem(hdlg, IDC_NOTICE_USER))
{
HBRUSH hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
SetTextColor((HDC)wParam, RGB(255, 0, 0));
return (LRESULT)hBrush;
}
break;
}
return FALSE;
}
#endif /* WIN32 */
#define ATTRIBUTE_DELIMITER ';'
#define OPENING_BRACKET '{'
#define CLOSING_BRACKET '}'
typedef BOOL (*copyfunc)(ConnInfo *, const char *attribute, char *value);
static BOOL
dconn_get_attributes(copyfunc func, const char *connect_string, ConnInfo *ci)
{
BOOL ret = TRUE;
char *our_connect_string;
char *pair,
*attribute,
*value,
*termp;
BOOL eoftok;
char *equals, *delp;
char *strtok_arg;
#ifdef HAVE_STRTOK_R
char *last = NULL;
#endif /* HAVE_STRTOK_R */
if (our_connect_string = strdup(connect_string), NULL == our_connect_string)
return FALSE;
strtok_arg = our_connect_string;
#ifdef FORCE_PASSWORD_DISPLAY
MYLOG(0, "our_connect_string = '%s'\n", our_connect_string);
#else
if (get_mylog())
{
char *hide_str = hide_password(our_connect_string);
MYLOG(0, "our_connect_string = '%s'\n", hide_str);
free(hide_str);
}
#endif /* FORCE_PASSWORD_DISPLAY */
termp = strchr(our_connect_string, '\0');
eoftok = FALSE;
while (!eoftok)
{
if (strtok_arg != NULL && strtok_arg >= termp) /* for safety */
break;
#ifdef HAVE_STRTOK_R
pair = strtok_r(strtok_arg, ";", &last);
#else
pair = strtok(strtok_arg, ";");
#endif /* HAVE_STRTOK_R */
if (strtok_arg)
strtok_arg = NULL;
if (!pair)
break;
equals = strchr(pair, '=');
if (!equals)
continue;
*equals = '\0';
attribute = pair; /* ex. DSN */
value = equals + 1; /* ex. 'CEO co1' */
/*
* Values enclosed with braces({}) can contain ; etc
* We don't remove the braces here because
* decode_or_remove_braces() in dlg_specifi.c
* would remove them later.
* Just correct the misdetected delimter(;).
*/
switch (*value)
{
const char *valuen, *closep;
case OPENING_BRACKET:
delp = strchr(value, '\0');
if (delp >= termp)
{
eoftok = TRUE;
break;
}
/* Where's a corresponding closing bracket? */
closep = strchr(value, CLOSING_BRACKET);
if (NULL != closep &&
closep[1] == '\0')
break;
for (valuen = value; valuen < termp; closep = strchr(valuen, CLOSING_BRACKET))
{
if (NULL == closep)
{
if (!delp) /* error */
{
MYLOG(0, "closing bracket doesn't exist 1\n");
ret = FALSE;
goto cleanup;
}
closep = strchr(delp + 1, CLOSING_BRACKET);
if (!closep) /* error */
{
MYLOG(0, "closing bracket doesn't exist 2\n");
ret = FALSE;
goto cleanup;
}
*delp = ATTRIBUTE_DELIMITER; /* restore delimiter */
delp = NULL;
}
if (CLOSING_BRACKET == closep[1])
{
valuen = closep + 2;
if (valuen >= termp)
break;
else if (valuen == delp)
{
*delp = ATTRIBUTE_DELIMITER;
delp = NULL;
}
continue;
}
else if (ATTRIBUTE_DELIMITER == closep[1] ||
'\0' == closep[1] ||
delp == closep + 1)
{
delp = (char *) (closep + 1);
*delp = '\0';
strtok_arg = delp + 1;
if (strtok_arg + 1 >= termp)
eoftok = TRUE;
break;
}
MYLOG(0, "subsequent char to the closing bracket is %c value=%s\n", closep[1], value);
ret = FALSE;
goto cleanup;
}
}
/* Copy the appropriate value to the conninfo */
(*func)(ci, attribute, value);
}
cleanup:
free(our_connect_string);
return ret;
}
static BOOL
dconn_get_DSN_or_Driver(const char *connect_string, ConnInfo *ci)
{
CC_conninfo_init(ci, INIT_GLOBALS);
return dconn_get_attributes(get_DSN_or_Driver, connect_string, ci);
}
static BOOL
dconn_get_connect_attributes(const char *connect_string, ConnInfo *ci)
{
return dconn_get_attributes(copyConnAttributes, connect_string, ci);
}
C
1
https://gitee.com/opengauss/openGauss-connector-odbc.git
git@gitee.com:opengauss/openGauss-connector-odbc.git
opengauss
openGauss-connector-odbc
openGauss-connector-odbc
master

搜索帮助