2020-07-06 12:23:36 +00:00
# include "SchemaAllowedHandler.h"
# if USE_ODBC
2024-07-11 12:00:05 +00:00
# include <Core/Settings.h>
2021-03-22 11:40:29 +00:00
# include <Server/HTTP/HTMLForm.h>
# include <Server/HTTP/WriteBufferFromHTTPServerResponse.h>
2024-07-11 12:00:05 +00:00
# include <IO/Operators.h>
2022-08-10 07:39:32 +00:00
# include <IO/ReadHelpers.h>
2021-03-22 11:40:29 +00:00
# include <IO/WriteHelpers.h>
# include <Poco/Net/HTTPServerRequest.h>
# include <Poco/Net/HTTPServerResponse.h>
2022-08-08 14:40:19 +00:00
# include <Common/BridgeProtocolVersion.h>
2022-04-27 15:05:45 +00:00
# include <Common/logger_useful.h>
2021-03-22 11:40:29 +00:00
# include "validateODBCConnectionString.h"
2022-06-01 09:00:39 +00:00
# include "ODBCPooledConnectionFactory.h"
2021-03-22 11:40:29 +00:00
# include <sql.h>
# include <sqlext.h>
2020-07-06 12:23:36 +00:00
namespace DB
{
2024-09-18 12:20:53 +00:00
namespace Setting
{
extern const SettingsUInt64 odbc_bridge_connection_pool_size ;
}
2020-07-06 12:23:36 +00:00
namespace
{
2021-06-07 18:09:16 +00:00
bool isSchemaAllowed ( nanodbc : : ConnectionHolderPtr connection_holder )
2020-07-06 12:23:36 +00:00
{
2021-06-07 18:09:16 +00:00
uint32_t result = execute < uint32_t > ( connection_holder ,
[ & ] ( nanodbc : : connection & connection ) { return connection . get_info < uint32_t > ( SQL_SCHEMA_USAGE ) ; } ) ;
2021-03-22 11:40:29 +00:00
return result ! = 0 ;
2020-07-06 12:23:36 +00:00
}
}
2024-01-03 16:47:15 +00:00
void SchemaAllowedHandler : : handleRequest ( HTTPServerRequest & request , HTTPServerResponse & response , const ProfileEvents : : Event & /*write_event*/ )
2020-07-06 12:23:36 +00:00
{
2021-06-16 14:33:14 +00:00
HTMLForm params ( getContext ( ) - > getSettingsRef ( ) , request , request . getStream ( ) ) ;
2020-07-06 12:23:36 +00:00
LOG_TRACE ( log , " Request URI: {} " , request . getURI ( ) ) ;
auto process_error = [ & response , this ] ( const std : : string & message )
{
response . setStatusAndReason ( Poco : : Net : : HTTPResponse : : HTTP_INTERNAL_SERVER_ERROR ) ;
if ( ! response . sent ( ) )
2024-01-03 16:47:15 +00:00
* response . send ( ) < < message < < ' \n ' ;
Use fmt::runtime() for LOG_* for non constexpr
Here is oneliner:
$ gg 'LOG_\(DEBUG\|TRACE\|INFO\|TEST\|WARNING\|ERROR\|FATAL\)([^,]*, [a-zA-Z]' -- :*.cpp :*.h | cut -d: -f1 | sort -u | xargs -r sed -E -i 's#(LOG_[A-Z]*)\(([^,]*), ([A-Za-z][^,)]*)#\1(\2, fmt::runtime(\3)#'
Note, that I tried to do this with coccinelle (tool for semantic
patchin), but it cannot parse C++:
$ cat fmt.cocci
@@
expression log;
expression var;
@@
-LOG_DEBUG(log, var)
+LOG_DEBUG(log, fmt::runtime(var))
I've also tried to use some macros/templates magic to do this implicitly
in logger_useful.h, but I failed to do so, and apparently it is not
possible for now.
Signed-off-by: Azat Khuzhin <a.khuzhin@semrush.com>
v2: manual fixes
Signed-off-by: Azat Khuzhin <a.khuzhin@semrush.com>
2022-02-01 09:10:27 +00:00
LOG_WARNING ( log , fmt : : runtime ( message ) ) ;
2020-07-06 12:23:36 +00:00
} ;
2022-08-10 07:39:32 +00:00
size_t version ;
2022-08-08 14:40:19 +00:00
if ( ! params . has ( " version " ) )
2022-08-10 07:39:32 +00:00
version = 0 ; /// assumed version for too old servers which do not send a version
2022-08-08 14:40:19 +00:00
else
{
String version_str = params . get ( " version " ) ;
2022-08-10 07:39:32 +00:00
if ( ! tryParse ( version , version_str ) )
2022-08-08 14:40:19 +00:00
{
process_error ( " Unable to parse 'version' string in request URL: ' " + version_str + " ' Check if the server and library-bridge have the same version. " ) ;
return ;
}
}
2022-08-10 07:39:32 +00:00
if ( version ! = XDBC_BRIDGE_PROTOCOL_VERSION )
{
/// backwards compatibility is considered unnecessary for now, just let the user know that the server and the bridge must be upgraded together
process_error ( " Server and library-bridge have different versions: ' " + std : : to_string ( version ) + " ' vs. ' " + std : : to_string ( LIBRARY_BRIDGE_PROTOCOL_VERSION ) + " ' " ) ;
return ;
}
2020-07-06 12:23:36 +00:00
if ( ! params . has ( " connection_string " ) )
{
process_error ( " No 'connection_string' in request URL " ) ;
return ;
}
2023-01-19 00:36:25 +00:00
bool use_connection_pooling = params . getParsed < bool > ( " use_connection_pooling " , true ) ;
2020-07-06 12:23:36 +00:00
try
{
std : : string connection_string = params . get ( " connection_string " ) ;
2021-04-06 18:59:34 +00:00
2023-01-19 00:36:25 +00:00
nanodbc : : ConnectionHolderPtr connection ;
if ( use_connection_pooling )
connection = ODBCPooledConnectionFactory : : instance ( ) . get (
2024-09-18 12:20:53 +00:00
validateODBCConnectionString ( connection_string ) , getContext ( ) - > getSettingsRef ( ) [ Setting : : odbc_bridge_connection_pool_size ] ) ;
2023-01-19 00:36:25 +00:00
else
connection = std : : make_shared < nanodbc : : ConnectionHolder > ( validateODBCConnectionString ( connection_string ) ) ;
2021-04-06 18:59:34 +00:00
2021-06-07 18:09:16 +00:00
bool result = isSchemaAllowed ( std : : move ( connection ) ) ;
2020-07-06 12:23:36 +00:00
2024-03-22 20:07:12 +00:00
WriteBufferFromHTTPServerResponse out ( response , request . getMethod ( ) = = Poco : : Net : : HTTPRequest : : HTTP_HEAD ) ;
2024-09-26 08:27:37 +00:00
writeBoolText ( result , out ) ;
out . finalize ( ) ;
2020-07-06 12:23:36 +00:00
}
catch ( . . . )
{
process_error ( " Error getting schema usage from ODBC ' " + getCurrentExceptionMessage ( false ) + " ' " ) ;
tryLogCurrentException ( log ) ;
}
}
}
# endif