-
Notifications
You must be signed in to change notification settings - Fork 192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for raw ODBC DSN connections. #54
base: master
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -576,7 +576,6 @@ static int conn_setautocommit (lua_State *L) { | |
return pass(L); | ||
} | ||
|
||
|
||
/* | ||
** Create a new Connection object and push it on top of the stack. | ||
*/ | ||
|
@@ -601,32 +600,135 @@ static int create_connection (lua_State *L, int o, env_data *env, SQLHDBC hdbc) | |
return 1; | ||
} | ||
|
||
/* | ||
** Uses a DSN string to connect to a ODBC source dynamically | ||
** Lua Input: { | ||
** dsn = <DSN string>, | ||
** } | ||
** Lua Returns: | ||
** connection object if successfull | ||
** nil and error message otherwise. | ||
*/ | ||
static int env_table_connect_DSN (lua_State *L) | ||
{ | ||
env_data *env = getenvironment (L); | ||
SQLCHAR *sourcename = (SQLCHAR *)luasql_table_optstring(L, 2, "dsn", NULL); | ||
|
||
SQLHDBC hdbc; | ||
SQLCHAR sqlOutBuf[4097]; | ||
SQLSMALLINT sqlOutLen; | ||
SQLRETURN ret; | ||
|
||
ret = SQLSetEnvAttr (env->henv, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0); | ||
if (error(ret)) { | ||
return luasql_faildirect (L, "error setting SQL version."); | ||
} | ||
|
||
/* tries to allocate connection handle */ | ||
ret = SQLAllocHandle (hDBC, env->henv, &hdbc); | ||
if (error(ret)) { | ||
return luasql_faildirect (L, "connection allocation error."); | ||
} | ||
|
||
/* tries to connect handle */ | ||
ret = SQLDriverConnect (hdbc, NULL, sourcename, SQL_NTS, sqlOutBuf, 4096, | ||
&sqlOutLen, SQL_DRIVER_NOPROMPT); | ||
if (error(ret)) { | ||
ret = fail(L, hDBC, hdbc); | ||
SQLFreeHandle(hDBC, hdbc); | ||
return ret; | ||
} | ||
|
||
/* success, return connection object */ | ||
ret = create_connection (L, 1, env, hdbc); | ||
if(ret == 1) { | ||
/* Add the sqlOutBuf string to the results, for diagnostics */ | ||
lua_pushlstring(L, (char *)sqlOutBuf, sqlOutLen); | ||
return 2; | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
/* | ||
** Creates and returns a connection object | ||
** Lua Input: source [, user [, pass]] | ||
** Reforms old connection style to new one | ||
** Lua Input: source, [user, [pass]] | ||
** source: data source | ||
** user, pass: data source authentication information | ||
** Lua Returns: | ||
** new connection details table | ||
*/ | ||
static void env_connect_fix_old (lua_State *L) | ||
{ | ||
static const char *const opt_names[] = { | ||
"source", | ||
"user", | ||
"password", | ||
NULL | ||
}; | ||
int i, t = lua_gettop(L)-1; | ||
|
||
lua_newtable(L); | ||
lua_insert(L, 2); | ||
|
||
for(i=0; opt_names[i] != NULL && i<t; ++i) { | ||
lua_pushstring(L, opt_names[i]); | ||
lua_pushvalue(L, i+3); | ||
lua_settable(L, 2); | ||
} | ||
|
||
lua_settop(L, 2); | ||
} | ||
|
||
/* | ||
** Creates and returns a connection object | ||
** Lua Input: { | ||
** source = <database source/path>, | ||
** user = <user name>, | ||
** password = <user password>, | ||
** or | ||
** dsn = <DSN string>, | ||
** } | ||
** Lua Returns: | ||
** connection object if successfull | ||
** nil and error message otherwise. | ||
*/ | ||
static int env_connect (lua_State *L) { | ||
env_data *env = (env_data *) getenvironment (L); | ||
SQLCHAR *sourcename = (SQLCHAR*)luaL_checkstring (L, 2); | ||
SQLCHAR *username = (SQLCHAR*)luaL_optstring (L, 3, NULL); | ||
SQLCHAR *password = (SQLCHAR*)luaL_optstring (L, 4, NULL); | ||
SQLHDBC hdbc; | ||
SQLRETURN ret; | ||
static int env_connect (lua_State *L) | ||
{ | ||
env_data *env = getenvironment (L); | ||
SQLCHAR *sourcename = NULL; | ||
SQLCHAR *username = NULL; | ||
SQLCHAR *password = NULL; | ||
SQLHDBC hdbc = NULL; | ||
SQLRETURN ret = 0; | ||
|
||
if(lua_gettop(L) < 2) { | ||
return luasql_faildirect(L, "No connection details provided"); | ||
} | ||
|
||
if(!lua_istable(L, 2)) { | ||
env_connect_fix_old(L); | ||
} | ||
|
||
/* check for the custom DSN connection string */ | ||
if(luasql_table_optstring(L, 2, "dsn", NULL) != NULL) { | ||
return env_table_connect_DSN(L); | ||
} | ||
|
||
/* get the standard connection details */ | ||
sourcename = (SQLCHAR *)luasql_table_optstring(L, 2, "source", NULL); | ||
username = (SQLCHAR *)luasql_table_optstring(L, 2, "user", NULL); | ||
password = (SQLCHAR *)luasql_table_optstring(L, 2, "password", NULL); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would just avoid the extra function altogether (and creating a table just to extract its values later), doing this: if(lua_istable(L, 2)) {
/* check for the custom DSN connection string */
if(luasql_table_optstring(L, 2, "dsn", NULL) != NULL) {
return env_table_connect_DSN(L);
}
/* get the standard connection details */
sourcename = (SQLCHAR *)luasql_table_optstring(L, 2, "source", NULL);
if (!sourcename) {
return luasql_faildirect (L, "no source given.");
}
username = (SQLCHAR *)luasql_table_optstring(L, 2, "user", NULL);
password = (SQLCHAR *)luasql_table_optstring(L, 2, "password", NULL);
} else {
sourcename = (SQLCHAR*)luaL_checkstring (L, 2);
username = (SQLCHAR*)luaL_optstring (L, 3, NULL);
password = (SQLCHAR*)luaL_optstring (L, 4, NULL);
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd suggest it provides an easy pattern for conversion of the other drivers to the more flexible named parameter style (which this patch shows a good case for) There's likely going to be additional params added here at some point (e.g. #36) and giving a clear, single place the values are picked up (along with a clear place for backward compatibility) seems a logical arrangement. The function inlines and the overhead of a table is nothing compared to the actual job of connecting to a DB. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In any case, note that the first argument used There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code still works fine (as in the connection fails as expected) |
||
|
||
/* tries to allocate connection handle */ | ||
ret = SQLAllocHandle (hDBC, env->henv, &hdbc); | ||
if (error(ret)) | ||
if (error(ret)) { | ||
return luasql_faildirect (L, "connection allocation error."); | ||
} | ||
|
||
/* tries to connect handle */ | ||
ret = SQLConnect (hdbc, sourcename, SQL_NTS, | ||
username, SQL_NTS, password, SQL_NTS); | ||
ret = SQLConnect (hdbc, sourcename, SQL_NTS, username, SQL_NTS, password, | ||
SQL_NTS); | ||
if (error(ret)) { | ||
ret = fail(L, hDBC, hdbc); | ||
SQLFreeHandle(hDBC, hdbc); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -131,3 +131,35 @@ LUASQL_API void luasql_set_info (lua_State *L) { | |
lua_pushliteral (L, "LuaSQL 2.3.0"); | ||
lua_settable (L, -3); | ||
} | ||
|
||
/* | ||
** Pulls an optional string value from the table at idx | ||
*/ | ||
LUASQL_API const char* luasql_table_optstring(lua_State *L, int idx, const char* name, const char* def) { | ||
const char* res = NULL; | ||
|
||
lua_pushstring(L, name); | ||
lua_gettable(L, idx); | ||
|
||
res = lua_tostring(L, -1); | ||
lua_pop(L, 1); | ||
|
||
return (res != NULL) ? res : def; | ||
} | ||
|
||
/* | ||
** Pulls an optional number value from the table at idx | ||
*/ | ||
LUASQL_API lua_Number luasql_table_optnumber(lua_State *L, int idx, const char* name, lua_Number def) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is not used anywhere, please remove |
||
lua_Number res = def; | ||
|
||
lua_pushstring(L, name); | ||
lua_gettable(L, idx); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe so, but not a 100% sure on that. A lot of issue around support across Lua versions, like the change in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @hishamhm can you comment on this, should keplerproject c libraries be Lua 5.0 compatible? (I personally don't think so, but maybe it still is a goal) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The last person who I saw keeping Lua 5.0 compatibility in any library was @tomasguisasola. Since he's maintaining LuaSQL drivers for his uses in production, he'd be the best person to ask. Tomás, do you still need 5.0 compatibility for anything? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi
Regards, On 2016-07-04 16:40, Hisham Muhammad wrote:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tomasguisasola so the compatibility with 5.0 can be removed? Challenges are fun, but so is replacing boilerplate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi Peter
Regards, On 2016-07-05 10:26, Peter Melnichenko wrote:
|
||
|
||
if(lua_isnumber(L, -1)) { | ||
res = lua_tonumber(L, -1); | ||
} | ||
lua_pop(L, 1); | ||
|
||
return res; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: replace terms such as "old" and "new"; over the years these definitions get outdated and stop making sense (e.g. what if a third way of connecting comes up? becomes
newer
?). I suggestenv_connect_convert_args_to_table
instead.Also, "fix" is a heavy term, because it implies something was "broken", when in this case it was clearly not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense