Skip to content

Commit

Permalink
#25 fix listing of tables and databases
Browse files Browse the repository at this point in the history
  • Loading branch information
artpaul committed Aug 3, 2017
1 parent 83260df commit 595a0ba
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 27 deletions.
20 changes: 17 additions & 3 deletions driver/attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ impl_SQLSetEnvAttr(SQLHENV environment_handle, SQLINTEGER attribute,
return SQL_SUCCESS;
}

case SQL_ATTR_METADATA_ID:
environment.metadata_id = (SQLUINTEGER)value;
return SQL_SUCCESS;

default:
throw std::runtime_error("Unsupported environment attribute.");
}
Expand All @@ -51,16 +55,19 @@ impl_SQLGetEnvAttr(SQLHENV environment_handle, SQLINTEGER attribute,
{
LOG(__FUNCTION__);

return doWith<Environment>(environment_handle, [&](Environment & environment)
return doWith<Environment>(environment_handle, [&](Environment & environment) -> RETCODE
{
LOG("attr: " << attribute);
const char * name = nullptr;

switch (attribute)
{
case SQL_ATTR_ODBC_VERSION:
fillOutputNumber<SQLUINTEGER>(environment.odbc_version, out_value, out_value_max_length, out_value_length);
return SQL_SUCCESS;

CASE_NUM(SQL_ATTR_METADATA_ID, SQLUINTEGER, environment.metadata_id);

case SQL_ATTR_CONNECTION_POOLING:
case SQL_ATTR_CP_MATCH:
case SQL_ATTR_OUTPUT_NTS:
Expand Down Expand Up @@ -92,12 +99,15 @@ impl_SQLSetConnectAttr(SQLHDBC connection_handle, SQLINTEGER attribute,
return SQL_SUCCESS;
}

case SQL_ATTR_CURRENT_CATALOG:
connection.database = stringFromSQLChar((SQLTCHAR *)value, value_length);
return SQL_SUCCESS;

case SQL_ATTR_ACCESS_MODE:
case SQL_ATTR_ASYNC_ENABLE:
case SQL_ATTR_AUTO_IPD:
case SQL_ATTR_AUTOCOMMIT:
case SQL_ATTR_CONNECTION_DEAD:
case SQL_ATTR_CURRENT_CATALOG:
case SQL_ATTR_METADATA_ID:
case SQL_ATTR_ODBC_CURSORS:
case SQL_ATTR_PACKET_SIZE:
Expand Down Expand Up @@ -176,6 +186,10 @@ impl_SQLSetStmtAttr(SQLHSTMT statement_handle, SQLINTEGER attribute,
statement.setScanEscapeSequences((SQLULEN)value != SQL_NOSCAN_ON);
return SQL_SUCCESS;

case SQL_ATTR_METADATA_ID:
statement.setMetadataId((SQLUINTEGER)value);
return SQL_SUCCESS;

case SQL_ATTR_APP_ROW_DESC:
case SQL_ATTR_APP_PARAM_DESC:
case SQL_ATTR_CURSOR_SCROLLABLE:
Expand Down Expand Up @@ -266,7 +280,7 @@ impl_SQLGetStmtAttr(SQLHSTMT statement_handle, SQLINTEGER attribute,
CASE_NUM(SQL_ATTR_ENABLE_AUTO_IPD, SQLULEN, SQL_FALSE);
CASE_NUM(SQL_ATTR_MAX_LENGTH, SQLULEN, 0);
CASE_NUM(SQL_ATTR_MAX_ROWS, SQLULEN, 0);
CASE_NUM(SQL_ATTR_METADATA_ID, SQLULEN, SQL_FALSE);
CASE_NUM(SQL_ATTR_METADATA_ID, SQLUINTEGER, statement.getMetadataId());
CASE_NUM(SQL_ATTR_NOSCAN, SQLULEN, (statement.getScanEscapeSequences() ? SQL_NOSCAN_OFF : SQL_NOSCAN_ON));
CASE_NUM(SQL_ATTR_QUERY_TIMEOUT, SQLULEN, 0);
CASE_NUM(SQL_ATTR_RETRIEVE_DATA, SQLULEN, SQL_RD_ON);
Expand Down
1 change: 1 addition & 0 deletions driver/environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ struct Environment
{"Array", TypeInfo{"TEXT", true, SQL_VARCHAR, 0xFFFFFF}},
};

SQLUINTEGER metadata_id = SQL_FALSE;
int odbc_version = SQL_OV_ODBC3_80;
DiagnosticRecord diagnostic_record;
};
2 changes: 1 addition & 1 deletion driver/info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ SQLGetInfo(HDBC connection_handle,
CASE_NUM(SQL_GETDATA_EXTENSIONS, SQLUINTEGER, SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND)
CASE_NUM(SQL_INDEX_KEYWORDS, SQLUINTEGER, SQL_IK_NONE)
CASE_NUM(SQL_INSERT_STATEMENT, SQLUINTEGER, SQL_IS_INSERT_LITERALS | SQL_IS_INSERT_SEARCHED)
CASE_NUM(SQL_SCHEMA_USAGE, SQLUINTEGER, SQL_SU_DML_STATEMENTS | SQL_SU_TABLE_DEFINITION)
CASE_NUM(SQL_SCROLL_OPTIONS, SQLUINTEGER, SQL_SO_FORWARD_ONLY)
CASE_NUM(SQL_SQL92_DATETIME_FUNCTIONS, SQLUINTEGER, SQL_SDF_CURRENT_DATE | SQL_SDF_CURRENT_TIME | SQL_SDF_CURRENT_TIMESTAMP)

Expand Down Expand Up @@ -236,6 +235,7 @@ SQLGetInfo(HDBC connection_handle,
CASE_FALLTHROUGH(SQL_STATIC_CURSOR_ATTRIBUTES2)
CASE_FALLTHROUGH(SQL_INFO_SCHEMA_VIEWS)
CASE_FALLTHROUGH(SQL_POS_OPERATIONS)
CASE_FALLTHROUGH(SQL_SCHEMA_USAGE)
CASE_FALLTHROUGH(SQL_SYSTEM_FUNCTIONS)
CASE_FALLTHROUGH(SQL_SQL92_FOREIGN_KEY_DELETE_RULE)
CASE_FALLTHROUGH(SQL_SQL92_FOREIGN_KEY_UPDATE_RULE)
Expand Down
89 changes: 69 additions & 20 deletions driver/odbc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ impl_SQLGetData(HSTMT statement_handle,
{
LOG(__FUNCTION__);

return doWith<Statement>(statement_handle, [&](Statement & statement)
return doWith<Statement>(statement_handle, [&](Statement & statement) -> RETCODE
{
if (column_or_param_number < 1 || column_or_param_number > statement.result.getNumColumns())
throw std::runtime_error("Column number is out of range.");
Expand Down Expand Up @@ -609,7 +609,7 @@ SQLGetDiagField(SQLSMALLINT handle_type, SQLHANDLE handle,
out_message_size);
}


/// Description: https://docs.microsoft.com/en-us/sql/relational-databases/native-client-odbc-api/sqltables
RETCODE SQL_API
SQLTables(HSTMT statement_handle,
SQLTCHAR * catalog_name, SQLSMALLINT catalog_name_length,
Expand All @@ -619,29 +619,78 @@ SQLTables(HSTMT statement_handle,
{
LOG(__FUNCTION__);

// TODO (artpaul) Take statement.getMetatadaId() into account.
return doWith<Statement>(statement_handle, [&](Statement & statement)
{
const std::string catalog = stringFromSQLChar(catalog_name, catalog_name_length);

std::stringstream query;

query << "SELECT"
// Get a list of all tables in all databases.
if (catalog_name != nullptr && catalog == SQL_ALL_CATALOGS &&
!schema_name && !table_name && !table_type)
{
query << "SELECT"
" database AS TABLE_CAT"
", '' AS TABLE_SCHEM"
", name AS TABLE_NAME"
", 'TABLE' AS TABLE_TYPE"
", '' AS REMARKS"
" FROM system.tables"
" WHERE (1 == 1)";

if (catalog_name)
query << " AND TABLE_CAT LIKE '" << stringFromSQLChar(catalog_name, catalog_name_length) << "'";
if (schema_name)
query << " AND TABLE_SCHEM LIKE '" << stringFromSQLChar(schema_name, schema_name_length) << "'";
if (table_name)
query << " AND TABLE_NAME LIKE '" << stringFromSQLChar(table_name, table_name_length) << "'";
/* if (table_type)
query << " AND TABLE_TYPE = '" << stringFromSQLChar(table_type, table_type_length) << "'";*/

query << " ORDER BY TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME";
" FROM system.tables"
" ORDER BY TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME";
}
// Get a list of all tables in the current database.
else if (!catalog_name && !schema_name && !table_name && !table_type)
{
query << "SELECT"
" database AS TABLE_CAT"
", '' AS TABLE_SCHEM"
", name AS TABLE_NAME"
", 'TABLE' AS TABLE_TYPE"
", '' AS REMARKS"
" FROM system.tables"
" WHERE (database == '";
query << statement.connection.database << "')";
query << " ORDER BY TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME";
}
// Get a list of databases on the current connection's server.
else if (!catalog.empty() &&
schema_name != nullptr && schema_name_length == 0 &&
table_name != nullptr && table_name_length == 0)
{
query << "SELECT"
" name AS TABLE_CAT"
", '' AS TABLE_SCHEM"
", '' AS TABLE_NAME"
", '' AS TABLE_TYPE"
", '' AS REMARKS"
" FROM system.databases"
" WHERE (1 == 1)";
query << " AND TABLE_CAT LIKE '" << catalog << "'";
query << " ORDER BY TABLE_CAT";
}
else
{
query << "SELECT"
" database AS TABLE_CAT"
", '' AS TABLE_SCHEM"
", name AS TABLE_NAME"
", 'TABLE' AS TABLE_TYPE"
", '' AS REMARKS"
" FROM system.tables"
" WHERE (1 == 1)";

if (catalog_name_length)
query << " AND TABLE_CAT LIKE '" << stringFromSQLChar(catalog_name, catalog_name_length) << "'";
if (schema_name_length)
query << " AND TABLE_SCHEM LIKE '" << stringFromSQLChar(schema_name, schema_name_length) << "'";
if (table_name_length)
query << " AND TABLE_NAME LIKE '" << stringFromSQLChar(table_name, table_name_length) << "'";
//if (table_type_length)
// query << " AND TABLE_TYPE = '" << stringFromSQLChar(table_type, table_type_length) << "'";

query << " ORDER BY TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME";
}

statement.setQuery(query.str());
statement.sendRequest();
Expand Down Expand Up @@ -685,13 +734,13 @@ SQLColumns(HSTMT statement_handle,
" FROM system.columns"
" WHERE (1 == 1)";

if (catalog_name)
if (catalog_name_length)
query << " AND TABLE_CAT LIKE '" << stringFromSQLChar(catalog_name, catalog_name_length) << "'";
if (schema_name)
if (schema_name_length)
query << " AND TABLE_SCHEM LIKE '" << stringFromSQLChar(schema_name, schema_name_length) << "'";
if (table_name)
if (table_name_length)
query << " AND TABLE_NAME LIKE '" << stringFromSQLChar(table_name, table_name_length) << "'";
if (column_name)
if (column_name_length)
query << " AND COLUMN_NAME LIKE '" << stringFromSQLChar(column_name, column_name_length) << "'";

query << " ORDER BY TABLE_CAT, TABLE_SCHEM, TABLE_NAME, ORDINAL_POSITION";
Expand Down
11 changes: 11 additions & 0 deletions driver/statement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

Statement::Statement(Connection & conn_)
: connection(conn_)
, metadata_id(conn_.environment.metadata_id)
{
ard.reset(new DescriptorClass);
apd.reset(new DescriptorClass);
Expand All @@ -24,6 +25,16 @@ void Statement::setScanEscapeSequences(bool value)
scan_escape_sequences = value;
}

SQLUINTEGER Statement::getMetadataId() const
{
return metadata_id;
}

void Statement::setMetadataId(SQLUINTEGER id)
{
metadata_id = id;
}

const std::string Statement::getQuery() const
{
return query;
Expand Down
10 changes: 10 additions & 0 deletions driver/statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ class Statement
/// Enable or disable scannign the SQL string for escape sequences.
void setScanEscapeSequences(bool value);

/// Returns current value of SQL_ATTR_METADATA_ID.
SQLUINTEGER getMetadataId() const;

/// Sets value of SQL_ATTR_METADATA_ID.
void setMetadataId(SQLUINTEGER id);

/// Returns original query.
const std::string getQuery() const;

Expand Down Expand Up @@ -76,6 +82,10 @@ class Statement
private:
std::unique_ptr<Poco::Net::HTTPResponse> response;

/// An SQLUINTEGER value that determines
/// how the string arguments of catalog functions are treated.
SQLUINTEGER metadata_id;

std::string query;
std::string prepared_query;
bool prepared = false;
Expand Down
10 changes: 7 additions & 3 deletions driver/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,21 @@ static const char * nextKeyValuePair(const char * data, const char * end, String
template <typename SIZE_TYPE>
std::string stringFromSQLChar(SQLTCHAR * data, SIZE_TYPE size)
{
if (!data)
if (!data || size == 0)
return {};

if (size < 0)
if (size == SQL_NTS)
{
#ifdef UNICODE
size = (SIZE_TYPE)wcslen(reinterpret_cast<LPCTSTR>(data));
#else
size = (SIZE_TYPE)strlen(reinterpret_cast<LPCTSTR>(data));
#endif
}
else if (size < 0)
{
throw std::runtime_error("invalid size of string : " + std::to_string(size));
}

#ifdef UNICODE
std::wstring wstr(reinterpret_cast<LPCTSTR>(data), static_cast<size_t>(size));
Expand Down

0 comments on commit 595a0ba

Please sign in to comment.