Skip to content

Commit

Permalink
Use select * from <table> limit 0 instead of com_field_list
Browse files Browse the repository at this point in the history
Summary:
com_field_list is marked as deprecated by mysql, so various tools may drop support of it. Old ProxySQL did not support this command,
 newer versions transform this command to `select * from <table> limit 0`. Therefore we can just use this query in the driver

Test Plan: CircleCI https://app.circleci.com/pipelines/github/memsql/singlestore-odbc-connector/1946/workflows/aa7adefc-8cc6-465b-99d2-64ecc1067e3f

Reviewers: amakarovych-ua, dPoltorak-ua

Reviewed By: amakarovych-ua

Subscribers: engineering-list

JIRA Issues: PLAT-5557

Differential Revision: https://grizzly.internal.memcompute.com/D52846
  • Loading branch information
Pavlo committed Nov 16, 2021
1 parent 2797d3d commit 043cbc0
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 75 deletions.
97 changes: 30 additions & 67 deletions ma_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -1386,7 +1386,7 @@ void MADB_InstallStmt(MADB_Stmt *Stmt, MYSQL_STMT *stmt)


/**
Get the table status for a table or tables using SHOW TABLE STATUS.
Get the table status for a table or tables using SHOW TABLES.
Lengths may not be SQL_NTS.
@param[in] stmt Handle to statement
Expand Down Expand Up @@ -1428,7 +1428,7 @@ MYSQL_RES *S2_ShowTables(MADB_Stmt *stmt,
if (table && *table)
{
strcat(query, "LIKE '");
cnt = mysql_real_escape_string(stmt->Connection->mariadb, tmpbuff, (char *)table, table_length);
cnt = mysql_real_escape_string(stmt->Connection->mariadb, tmpbuff, (char *)table, table_length);
strncat(query, tmpbuff, cnt);
strcat(query, "'");
}
Expand Down Expand Up @@ -1486,7 +1486,7 @@ MYSQL_RES *S2_ShowColumnsInTable(MADB_Stmt *stmt,
if (column_like && *column_like && column_length)
{
strcat(query, " LIKE '");
cnt = mysql_real_escape_string(stmt->Connection->mariadb, tmpbuff, (char *)column_like, column_length);
cnt = mysql_real_escape_string(stmt->Connection->mariadb, tmpbuff, (char *)column_like, column_length);
strncat(query, tmpbuff, cnt);
strcat(query, "'");
}
Expand Down Expand Up @@ -1617,76 +1617,39 @@ MYSQL_RES *S2_ShowKeysInTable(MADB_Stmt *stmt,
return mysql_store_result(stmt->Connection->mariadb);
}


MYSQL_RES *
S2_ListFields(MADB_Stmt *stmt,
SQLCHAR *catalog,
SQLSMALLINT catalog_length,
SQLCHAR *table,
SQLSMALLINT table_length,
SQLCHAR *column_like,
SQLSMALLINT column_length)
MYSQL_RES *S2_ListFields(MADB_Stmt *stmt,
SQLCHAR *catalog,
SQLSMALLINT catalog_length,
SQLCHAR *table,
SQLSMALLINT table_length)
{
MYSQL_RES *result;
char buff[NAME_LEN * 2 + 64], column_buff[NAME_LEN * 2 + 64];
char *current_db;
if (stmt->Connection->mariadb->db)
{
current_db = strdup(stmt->Connection->mariadb->db);
}
else
{
current_db = NULL;
}
if (table_length <= 0 || !table)
{
return NULL;
}
MADB_DynString query;
MADB_InitDynamicString(&query, "SELECT * FROM ", 1024, 512);

/* If a catalog was specified, we have to change working catalog
to be able to use mysql_list_fields. */
int need_db_change = !current_db || (catalog_length > 0 && catalog && strcmp(current_db, catalog));
if (need_db_change)
{
strncpy(buff, (const char*)catalog, catalog_length);
buff[catalog_length]= '\0';
if (catalog && *catalog)
{
MADB_DynstrAppend(&query, "`");
MADB_DynstrAppendMem(&query, catalog, catalog_length);
MADB_DynstrAppend(&query, "`");
MADB_DynstrAppend(&query, ".");
}

if (mysql_select_db(stmt->Connection->mariadb, buff))
{
return NULL;
}
}
strcpy(buff, "`");
strncat(buff, (const char*)table, table_length);
strcat(buff, "`");
if (column_length > 0)
{
strncpy(column_buff, (const char *) column_like, column_length);
column_buff[column_length] = '\0';
fflush(stdout);
result = mysql_list_fields(stmt->Connection->mariadb, buff, column_buff);
}
else
{
result = mysql_list_fields(stmt->Connection->mariadb, buff, NULL);
}
if (!result)
MADB_DynstrAppend(&query, "`");
MADB_DynstrAppendMem(&query, table, table_length);
MADB_DynstrAppend(&query, "`");

MADB_DynstrAppend(&query, " LIMIT 0");

LOCK_MARIADB(stmt->Connection);
if (mysql_real_query(stmt->Connection->mariadb, query.str, query.length))
{
MADB_DynstrFree(&query);
UNLOCK_MARIADB(stmt->Connection);
MADB_SetError(&stmt->Error, MADB_ERR_HY001, mysql_error(stmt->Connection->mariadb), mysql_errno(stmt->Connection->mariadb));
free(current_db);
return NULL;
}
MADB_DynstrFree(&query);
UNLOCK_MARIADB(stmt->Connection);

if (current_db && need_db_change)
{
if (mysql_select_db(stmt->Connection->mariadb, current_db))
{
MADB_SetError(&stmt->Error, MADB_ERR_HY001, mysql_error(stmt->Connection->mariadb), mysql_errno(stmt->Connection->mariadb));
mysql_free_result(result);
free(current_db);
return NULL;
}
}
free(current_db);
return result;
return mysql_store_result(stmt->Connection->mariadb);
}
4 changes: 1 addition & 3 deletions ma_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,7 @@ S2_ListFields(MADB_Stmt *stmt,
SQLCHAR *catalog,
SQLSMALLINT catalog_length,
SQLCHAR *table,
SQLSMALLINT table_length,
SQLCHAR *column_like,
SQLSMALLINT column_length);
SQLSMALLINT table_length);

MYSQL_RES *S2_ShowColumnsInTable(MADB_Stmt *stmt,
SQLCHAR *catalog,
Expand Down
8 changes: 4 additions & 4 deletions ma_statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -4758,7 +4758,7 @@ SQLRETURN MADB_StmtColumnsNoInfoSchema(MADB_Stmt *Stmt,
if (ColumnName && NameLength4 <= 0)
NameLength4 = strlen(ColumnName);

// TODO: set force_db_charset to 0 for engine versions where the correct utf8mb4 charsetnr is reported
// TODO: PLAT-5907 set force_db_charset to 0 for engine versions where the correct utf8mb4 charsetnr is reported
int force_db_charset = single_store_get_server_version(Stmt->Connection->mariadb) >= 70500;

// get the list of matching tables
Expand All @@ -4781,9 +4781,9 @@ SQLRETURN MADB_StmtColumnsNoInfoSchema(MADB_Stmt *Stmt,
{
table_lengths = mysql_fetch_lengths(tables_res);

// for each table get the list of matching columns in the table
// for each table get the list of columns in it
if (!(columns_res = S2_ListFields(
Stmt, CatalogName, NameLength1, table_row[0], table_lengths[0], ColumnName, NameLength4)))
Stmt, CatalogName, NameLength1, table_row[0], table_lengths[0])))
{
free(formatted_table_ptr);
mysql_free_result(tables_res);
Expand Down Expand Up @@ -4846,7 +4846,7 @@ SQLRETURN MADB_StmtColumnsNoInfoSchema(MADB_Stmt *Stmt,
else
{
// in this case field is filtered by column_like in `SHOW COLUMNS FROM ... LIKE <column_like>`
// so we should skip it indeed. mysql_list_fields doesn't apply filter for some reason
// so we should skip it indeed.
continue;
}
// TABLE_CAT
Expand Down
90 changes: 90 additions & 0 deletions test/sqlcolumns.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,63 @@ int run_sql_columns(SQLHANDLE Stmt, const SQLSMALLINT *ExpDataType, const SQLSMA
return OK;
}

#define N_COLUMNS_LARGE 520
int run_sql_columns_large(SQLHANDLE Stmt, const SQLSMALLINT *ExpDataType, const SQLSMALLINT *ExpSqlDataType) {
char query[N_COLUMNS_LARGE * 20 + 40] = "CREATE TABLE t_types (";
int i;
for (i = 0; i < N_COLUMNS_LARGE; i++)
{
sprintf(query + strlen(query), "c_%d INT,", i);
}
sprintf(query + strlen(query), "c_%d INT)", i);
OK_SIMPLE_STMT(Stmt, "DROP TABLE IF EXISTS t_types");
OK_SIMPLE_STMT(Stmt, query);


CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLColumns(Stmt, my_schema, SQL_NTS, NULL, 0,
(SQLCHAR *) "t_types", SQL_NTS, NULL, 0));

SQLCHAR tableCat[SQL_COLUMNS_BUFFER_LEN], tableSchema[SQL_COLUMNS_BUFFER_LEN], tableName[SQL_COLUMNS_BUFFER_LEN], colName[SQL_COLUMNS_BUFFER_LEN], typeName[SQL_COLUMNS_BUFFER_LEN];
SQLCHAR remarks[SQL_COLUMNS_BUFFER_LEN], colDefault[SQL_COLUMNS_BUFFER_LEN], isNullable[SQL_COLUMNS_BUFFER_LEN];
SQLLEN tsSize, csSize, blSize, ddSize, nprSize, rSize, cdSize, dscSize, colSize;
SQLSMALLINT dataType, decimalDigits, numPrecRadix, nullable, sqlDataType, datetimeSubtypeCode;
SQLINTEGER columnSize, charOctetLength, bufferLength, ordinalPosition;

// Bind columns in result set to buffers
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 1, SQL_C_CHAR, tableCat, SQL_COLUMNS_BUFFER_LEN, NULL));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 2, SQL_C_CHAR, tableSchema, SQL_COLUMNS_BUFFER_LEN, &tsSize));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 3, SQL_C_CHAR, tableName, SQL_COLUMNS_BUFFER_LEN, NULL));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 4, SQL_C_CHAR, colName, SQL_COLUMNS_BUFFER_LEN, NULL));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 5, SQL_C_SHORT, &dataType, 0, NULL));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 6, SQL_C_CHAR, typeName, SQL_COLUMNS_BUFFER_LEN, NULL));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 7, SQL_C_LONG, &columnSize, 0, &csSize));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 8, SQL_C_LONG, &bufferLength, 0, &blSize));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 9, SQL_C_SHORT, &decimalDigits, 0, &ddSize));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 10, SQL_C_SHORT, &numPrecRadix, 0, &nprSize));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 11, SQL_C_SHORT, &nullable, 0, NULL));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 12, SQL_C_CHAR, remarks, SQL_COLUMNS_BUFFER_LEN, &rSize));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 13, SQL_C_CHAR, colDefault, SQL_COLUMNS_BUFFER_LEN, &cdSize));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 14, SQL_C_SHORT, &sqlDataType, 0, NULL));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 15, SQL_C_SHORT, &datetimeSubtypeCode, 0, &dscSize));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 16, SQL_C_LONG, &charOctetLength, 0, &colSize));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 17, SQL_C_LONG, &ordinalPosition, 0, NULL));
CHECK_HANDLE_RC(SQL_HANDLE_STMT, Stmt, SQLBindCol(Stmt, 18, SQL_C_CHAR, isNullable, SQL_COLUMNS_BUFFER_LEN, NULL));

int rc;
int numOfRowsFetched = 0;
while ((rc = SQLFetch(Stmt)) == SQL_SUCCESS)
{
char expColName[7];
sprintf(expColName, "c_%d", numOfRowsFetched);

FAIL_IF(_stricmp(colName, expColName) != 0, "Wrong COLUMN_NAME returned!");
is_num(ordinalPosition, ++numOfRowsFetched);
is_num(dataType, SQL_INTEGER);
}
diag("Fetched %d rows", numOfRowsFetched);
return OK;
}

ODBC_TEST(t_columns3U) {
SQLSMALLINT ExpDataType[33] = {SQL_TINYINT, SQL_SMALLINT, SQL_INTEGER, SQL_INTEGER, SQL_BIGINT, SQL_DOUBLE,
SQL_REAL,
Expand Down Expand Up @@ -318,12 +375,45 @@ ODBC_TEST(t_columns2A) {
return OK;
}

ODBC_TEST(t_columns_long) {
SQLSMALLINT ExpDataType[N_COLUMNS_LARGE] = {SQL_INTEGER};
SQLSMALLINT ExpSqlDataType[N_COLUMNS_LARGE] = {SQL_INTEGER};

SQLHANDLE henv1;
SQLHANDLE Connection1;
SQLHANDLE Stmt1;
SQLCHAR conn[512];

sprintf((char *) conn, "DRIVER=%s;SERVER=%s;UID=%s;PASSWORD=%s;DATABASE=%s;%s;%s",
my_drivername, my_servername, my_uid, my_pwd, my_schema, ma_strport, add_connstr);

CHECK_ENV_RC(henv1, SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv1));
CHECK_ENV_RC(henv1, SQLSetEnvAttr(henv1, SQL_ATTR_ODBC_VERSION,
(SQLPOINTER) SQL_OV_ODBC2, SQL_IS_INTEGER));
CHECK_ENV_RC(henv1, SQLAllocHandle(SQL_HANDLE_DBC, henv1, &Connection1));
CHECK_DBC_RC(Connection1,
SQLDriverConnect(Connection1, NULL, conn, (SQLSMALLINT) strlen((const char *) conn), NULL, 0,
NULL, SQL_DRIVER_NOPROMPT));
CHECK_DBC_RC(Connection1, SQLAllocHandle(SQL_HANDLE_STMT, Connection1, &Stmt1));

FAIL_IF(run_sql_columns_large(Stmt1, ExpDataType, ExpSqlDataType) != OK, "error running SQLColumns with 300 columns");

CHECK_STMT_RC(Stmt1, SQLFreeHandle(SQL_HANDLE_STMT, Stmt1));
CHECK_DBC_RC(Connection1, SQLDisconnect(Connection1));
CHECK_DBC_RC(Connection1, SQLFreeHandle(SQL_HANDLE_DBC, Connection1));
CHECK_ENV_RC(henv1, SQLFreeHandle(SQL_HANDLE_ENV, henv1));

return OK;
}


MA_ODBC_TESTS my_tests[] =
{
{t_columns3U, "t_columns3U", NORMAL, UNICODE_DRIVER},
{t_columns3A, "t_columns3A", NORMAL, ANSI_DRIVER},
{t_columns2U, "t_columns2U", NORMAL, UNICODE_DRIVER},
{t_columns2A, "t_columns2A", NORMAL, ANSI_DRIVER},
{t_columns_long, "t_columns_long", NORMAL, ALL_DRIVERS},
{NULL, NULL, NORMAL, ALL_DRIVERS}
};

Expand Down
2 changes: 1 addition & 1 deletion test/tap.h
Original file line number Diff line number Diff line change
Expand Up @@ -1647,7 +1647,7 @@ int getDbCharSize()
}
if (!strncmp(collation, "utf8mb4", 7))
char_size = 4;
if (!strncmp(collation, "utf8", 4))
else if (!strncmp(collation, "utf8", 4))
char_size = 3;
mysql_free_result(res);
mysql_close(mysql);
Expand Down

0 comments on commit 043cbc0

Please sign in to comment.