Skip to content
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

SNOW-1358461: Issue with metadata query for columns #1746

Closed
jb-saurabh opened this issue May 1, 2024 · 8 comments
Closed

SNOW-1358461: Issue with metadata query for columns #1746

jb-saurabh opened this issue May 1, 2024 · 8 comments
Assignees
Labels
invalid status-triage_done Initial triage done, will be further handled by the driver team

Comments

@jb-saurabh
Copy link

jb-saurabh commented May 1, 2024

I am utilizing the getColumns method of SnowflakeDatabaseMetaData class. As I debug I found that internally it makes query:
show /* JDBC:DatabaseMetaData.getColumns() */ columns in database "MY_DB_NAME",

If my schema or table name includes underscore (_) like A_BC in the name because it checks for wildcard patterns internally, and if it finds any, it creates a query for the entire metadata instead of just the table.
like: If there is _ in Schema name
show /* JDBC:DatabaseMetaData.getColumns() */ columns in database " ABC_DATABASE"

Expecting:
If I am providing all details like Database, Schema, and Table name with or without underscore (_) like A_BC then it should create a query like:
show /* JDBC:DatabaseMetaData.getColumns() */ columns in table "MY_DB_NAME"."MY_SCHEMA_NAME"."MY_TABLE_NAME"

Library:

 <dependency>
       <groupId>net.snowflake</groupId>
       <artifactId>snowflake-jdbc</artifactId>
       <version>3.13.6</version>
</dependency> 

Responsible code:

 String showColumnsCommand = "show /* JDBC:DatabaseMetaData.getColumns() */ columns";

    if (columnNamePattern != null
        && !columnNamePattern.isEmpty()
        && !columnNamePattern.trim().equals("%")
        && !columnNamePattern.trim().equals(".*")) {
      showColumnsCommand += " like '" + escapeSingleQuoteForLikeCommand(columnNamePattern) + "'";
    }

    if (catalog == null) {
      showColumnsCommand += " in account";
    } else if (catalog.isEmpty()) {
      return SnowflakeDatabaseMetaDataResultSet.getEmptyResultSet(
          extendedSet ? GET_COLUMNS_EXTENDED_SET : GET_COLUMNS, statement);
    } else {
      String catalogEscaped = escapeSqlQuotes(catalog);
      if (schemaPattern == null || isSchemaNameWildcardPattern(schemaPattern)) {
        showColumnsCommand += " in database \"" + catalogEscaped + "\"";
      } else if (schemaPattern.isEmpty()) {
        return SnowflakeDatabaseMetaDataResultSet.getEmptyResultSet(
            extendedSet ? GET_COLUMNS_EXTENDED_SET : GET_COLUMNS, statement);
      } else {
        String schemaUnescaped = unescapeChars(schemaPattern);
        if (tableNamePattern == null || Wildcard.isWildcardPatternStr(tableNamePattern)) {
          showColumnsCommand += " in schema \"" + catalogEscaped + "\".\"" + schemaUnescaped + "\"";
        } else if (tableNamePattern.isEmpty()) {
          return SnowflakeDatabaseMetaDataResultSet.getEmptyResultSet(
              extendedSet ? GET_COLUMNS_EXTENDED_SET : GET_COLUMNS, statement);
        } else {
          String tableNameUnescaped = unescapeChars(tableNamePattern);
          showColumnsCommand +=
              " in table \""
                  + catalogEscaped
                  + "\".\""
                  + schemaUnescaped
                  + "\".\""
                  + tableNameUnescaped
                  + "\"";
        }
      }
    }

I have also checked the recently released version 3.16.0 but still happening the same. https://github.com/snowflakedb/snowflake-jdbc/blob/master/src/main/java/net/snowflake/client/jdbc/SnowflakeDatabaseMetaData.java#L1674

@jb-saurabh jb-saurabh added the bug label May 1, 2024
@github-actions github-actions bot changed the title Issue with metadata query for columns SNOW-1358461: Issue with metadata query for columns May 1, 2024
@sfc-gh-sghosh sfc-gh-sghosh self-assigned this May 2, 2024
@sfc-gh-sghosh
Copy link
Contributor

Hello @jb-saurabh ,

Thanks for raising the question.

Did you try setting the parameter CLIENT_METADATA_REQUEST_USE_CONNECTION_CTX=true, this parameter can change the default search scope from all databases/schemas to the current database/schema. The narrower search typically returns fewer rows and executes more quickly.

Documentation:
https://docs.snowflake.com/en/sql-reference/parameters
search for CLIENT_METADATA_REQUEST_USE_CONNECTION_CTX

let us know if you still facing the issue after setting below parameter.

Example

`stmt.execute("alter session set CLIENT_METADATA_REQUEST_USE_CONNECTION_CTX = true");

DatabaseMetaData dbmd = con.getMetaData();
System.out.println("Metadata:");
System.out.println("================================");
// fetch metadata

ResultSet columns = dbmd.getColumns(null, "_TEST", null, null);
  //Printing the column name and size
  while (columns.next()){
    System.out.print("Column name and size: "+columns.getString("COLUMN_NAME"));
    System.out.print("("+columns.getInt("COLUMN_SIZE")+")");
    System.out.println(" ");
    System.out.println("Ordinal position: "+columns.getInt("ORDINAL_POSITION"));
    System.out.println("Catalog: "+columns.getString("TABLE_CAT"));
    System.out.println("Data type (integer value): "+columns.getInt("DATA_TYPE"));
    System.out.println("Data type name: "+columns.getString("TYPE_NAME"));
    System.out.println(" ");
  }

`

Regards,
Sujan

@sfc-gh-sghosh sfc-gh-sghosh added status-triage Issue is under initial triage and removed bug labels May 2, 2024
@jb-saurabh
Copy link
Author

Hello @jb-saurabh ,

Thanks for raising the question.

Did you try setting the parameter CLIENT_METADATA_REQUEST_USE_CONNECTION_CTX=true, this parameter can change the default search scope from all databases/schemas to the current database/schema. The narrower search typically returns fewer rows and executes more quickly.

Documentation: https://docs.snowflake.com/en/sql-reference/parameters search for CLIENT_METADATA_REQUEST_USE_CONNECTION_CTX

let us know if you still facing the issue after setting below parameter.

Example

`stmt.execute("alter session set CLIENT_METADATA_REQUEST_USE_CONNECTION_CTX = true");

DatabaseMetaData dbmd = con.getMetaData(); System.out.println("Metadata:"); System.out.println("================================"); // fetch metadata

ResultSet columns = dbmd.getColumns(null, "_TEST", null, null);
  //Printing the column name and size
  while (columns.next()){
    System.out.print("Column name and size: "+columns.getString("COLUMN_NAME"));
    System.out.print("("+columns.getInt("COLUMN_SIZE")+")");
    System.out.println(" ");
    System.out.println("Ordinal position: "+columns.getInt("ORDINAL_POSITION"));
    System.out.println("Catalog: "+columns.getString("TABLE_CAT"));
    System.out.println("Data type (integer value): "+columns.getInt("DATA_TYPE"));
    System.out.println("Data type name: "+columns.getString("TYPE_NAME"));
    System.out.println(" ");
  }

`

Regards, Sujan

Hi @sfc-gh-sghosh,
Thanks for answering,
I tried the steps you have above mentioned but I remain stuck because it is not executing for the table. As I read this doc(https://docs.snowflake.com/en/sql-reference/parameters#label-client-metadata-request-use-connection-ctx), here is mentioned if we are not providing database or schema name with this property, it will narrow the search to the current database and schema specified by the connection context. But I don't want to load the database or schema if I am providing all details, I want to directly load table metadata instead of loading the database or schema.

@sfc-gh-sghosh
Copy link
Contributor

Hello @jb-saurabh ,

Thanks for the update.
The correct syntax for the DatabaseMetaData getColumns() is ( catalog, schemaPattern, TableNamePattern, SchemaNamePattern), All are strings datatype.

I just tested it again, its perfectly narrow down to the current schema and database ( which is being used in the connection URL ) and will only search the respective table.

If you pass the respective catalog and scehma, then it will search from that specific catalog and schema.
ResultSet columns = dbmd.getColumns("SAMPLEDATABASE", "TEST", "MYCSVTABLE", null);

if you do not pass any database or catalog, then its recommended to use the below parameter CLIENT_METADATA_REQUEST_USE_CONNECTION_CTX .

I am getting same output for both the case.

Example: I am not passing the database or schema (its null) , I am passing only the tablename.

stmt.execute("alter session set CLIENT_METADATA_REQUEST_USE_CONNECTION_CTX = true");

ResultSet columns = dbmd.getColumns(null, null, "MYCSVTABLE", null);
//Printing the column name and size
while (columns.next()){
System.out.print("Table name and size: "+columns.getString("TABLE_NAME"));
System.out.println("Catalog: "+columns.getString("TABLE_CAT"));
System.out.print("Column name and size: "+columns.getString("COLUMN_NAME"));
System.out.print("("+columns.getInt("COLUMN_SIZE")+")");
System.out.println(" ");
System.out.println("Ordinal position: "+columns.getInt("ORDINAL_POSITION"));
System.out.println("Data type (integer value): "+columns.getInt("DATA_TYPE"));
System.out.println("Data type name: "+columns.getString("TYPE_NAME"));
System.out.println(" ");
}

Output:
Its only printing the columns info the table MYCSVTABLE and no other table

Get columns
Table name and size: MYCSVTABLE Catalog: SAMPLEDATABASE
Column name and size: SEQ(38)
Ordinal position: 1
Data type (integer value): -5
Data type name: NUMBER

Table name and size: MYCSVTABLE Catalog: SAMPLEDATABASE
Column name and size: LAST_NAME(50)
Ordinal position: 2
Data type (integer value): 12
Data type name: VARCHAR

Table name and size: MYCSVTABLE Catalog: SAMPLEDATABASE
Column name and size: FIRST_NAME(50)
Ordinal position: 3
Data type (integer value): 12
Data type name: VARCHAR

So, please try again and let us know your code if still doesnt work.

Regards,
Sujan

@sfc-gh-sghosh sfc-gh-sghosh added the status-information_needed Additional information is required from the reporter label May 6, 2024
@jb-saurabh
Copy link
Author

Hi @sfc-gh-sghosh,
Thanks for your response.
Yes, you are correct, it working as expected for dbmd.getColumns("SAMPLEDATABASE", "TEST", "MYCSVTABLE", null);

But my issue is when I am providing a schema name like TEST_SCHEMA and a table name like MY_CSVTABLE then it will load metadata for the complete database. And query will be become something like: show /* JDBC:DatabaseMetaData.getColumns() */ columns in database "SAMPLEDATABASE"

Concludingly It should working as expected for dbmd.getColumns("SAMPLEDATABASE", "TEST_SCHEMA ", "MY_CSVTABLE ", null);

@sfc-gh-wfateem sfc-gh-wfateem self-assigned this May 7, 2024
@sfc-gh-wfateem
Copy link
Collaborator

@jb-saurabh That method supports pattern matching, but the _ character will match any character, so you would need to escape that in order to get the output you're looking for. Please refer to the documentation here for more information.

@sfc-gh-wfateem
Copy link
Collaborator

@jb-saurabh have you tried escaping the underscore character and confirm that you get the expected output?

@jb-saurabh
Copy link
Author

Hi @sfc-gh-wfateem
Thanks for your response.
Yes, I tried this way as you suggested and it works for me.
Thank You!

@sfc-gh-wfateem sfc-gh-wfateem added status-triage_done Initial triage done, will be further handled by the driver team question Issue is a usage/other question rather than a bug invalid and removed status-triage Issue is under initial triage status-information_needed Additional information is required from the reporter question Issue is a usage/other question rather than a bug labels May 9, 2024
@sfc-gh-wfateem
Copy link
Collaborator

Thanks for confirming @jb-saurabh
I'll go ahead and close off this issue then.
Don't hesitate to reach out again if you run into any other issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
invalid status-triage_done Initial triage done, will be further handled by the driver team
Projects
None yet
Development

No branches or pull requests

3 participants