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

Implementation of the Connection.GetSchema of the DataSourceInformation collection #190

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions DuckDB.NET.Data/DuckDBSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System.Linq;
using System.Text;

using DuckDB.NET.Native;

namespace DuckDB.NET.Data;

internal static class DuckDBSchema
Expand All @@ -20,6 +22,7 @@ public static DataTable GetSchema(DuckDBConnection connection, string collection
collectionName.ToUpperInvariant() switch
{
"METADATACOLLECTIONS" => GetMetaDataCollections(),
"DATASOURCEINFORMATION" => GetDataSourceInformation(connection.ServerVersion),
"RESTRICTIONS" => GetRestrictions(),
"RESERVEDWORDS" => GetReservedWords(connection),
"TABLES" => GetTables(connection, restrictionValues),
Expand All @@ -41,6 +44,7 @@ private static DataTable GetMetaDataCollections() =>
Rows =
{
{ DbMetaDataCollectionNames.MetaDataCollections, 0, 0 },
{ DbMetaDataCollectionNames.DataSourceInformation, 0, 0 },
{ DbMetaDataCollectionNames.Restrictions, 0, 0 },
{ DbMetaDataCollectionNames.ReservedWords, 0, 0 },
{ DuckDbMetaDataCollectionNames.Tables, TableRestrictions.Length, 3 },
Expand All @@ -50,6 +54,62 @@ private static DataTable GetMetaDataCollections() =>
}
};

private static DataTable GetDataSourceInformation(string? serverVersion) =>
new(DbMetaDataCollectionNames.DataSourceInformation) {
Columns =
{
{ DbMetaDataColumnNames.CompositeIdentifierSeparatorPattern, typeof(string) },
{ DbMetaDataColumnNames.DataSourceProductName, typeof(string) },
{ DbMetaDataColumnNames.DataSourceProductVersion, typeof(string) },
{ DbMetaDataColumnNames.DataSourceProductVersionNormalized, typeof(string) },
{ DbMetaDataColumnNames.GroupByBehavior, typeof(GroupByBehavior) },
{ DbMetaDataColumnNames.IdentifierPattern, typeof(string) },
{ DbMetaDataColumnNames.IdentifierCase, typeof(IdentifierCase) },
{ DbMetaDataColumnNames.OrderByColumnsInSelect, typeof(bool) },
{ DbMetaDataColumnNames.ParameterMarkerFormat, typeof(string) },
{ DbMetaDataColumnNames.ParameterMarkerPattern, typeof(string) },
{ DbMetaDataColumnNames.ParameterNameMaxLength, typeof(int) },
{ DbMetaDataColumnNames.ParameterNamePattern, typeof(string) },
{ DbMetaDataColumnNames.QuotedIdentifierPattern, typeof(string) },
{ DbMetaDataColumnNames.QuotedIdentifierCase, typeof(IdentifierCase) },
{ DbMetaDataColumnNames.StatementSeparatorPattern, typeof(string) },
{ DbMetaDataColumnNames.StringLiteralPattern, typeof(string) },
{ DbMetaDataColumnNames.SupportedJoinOperators, typeof(SupportedJoinOperators) }
},
Rows =
{
// For more information about pattern, parameters and so on go to:
// https://duckdb.org/docs/sql/keywords_and_identifiers.html
// https://duckdb.org/docs/sql/query_syntax/prepared_statements
{
"\\.",
"DuckDB",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you return “DuckDB”, but test checks for “duckdb” (lowercase)

serverVersion,
serverVersion,
GroupByBehavior.Unrelated,
// strings that begin with a single special character ($, letter, or underscore) followed by zero or more alphanumeric characters, underscore, $
// or strings that begin with a double quote followed by one or more any characters (except double quotes or null character)
"(^\\[\\p{Lo}\\p{Lu}\\p{Ll}_$][\\p{Lo}\\p{Lu}\\p{Ll}\\p{Nd}$$_]*$)|(^\\\"[^\\\"\\0]|\\\"\\\"+\\\"$)",
IdentifierCase.Insensitive,
false,
"{0}",
// identifies strings composed of letters, numbers, underscores and $
"$[\\p{Lo}\\p{Lu}\\p{Ll}\\p{Lm}_$][\\p{Lo}\\p{Lu}\\p{Ll}\\p{Lm}\\p{Nd}\\uff3f_$\\$]*(?=\\s+|$)",
128,
// This regexp matches a string that begins with a letter, number, underscore, or dollar sign, and can contain other similar characters, numbers, question marks, underscores, dollar signs, and white spaces.
// The string must end with white space or the end of the string.
"^[\\p{Lo}\\p{Lu}\\p{Ll}\\p{Lm}_$][\\p{Lo}\\p{Lu}\\p{Ll}\\p{Lm}\\p{Nd}\\uff3f_$\\$]*(?=\\s+|$)",
// This regexp is used to find a sequence of characters that does not contain double quote or contains them in pairs.
"((\"^\\\"\"|\\\"\\\")*)",
IdentifierCase.Insensitive,
";",
// The regexp is used to find a sequence of one or more characters, excluding single quotes (').
"'(([^']|'')*)'",
SupportedJoinOperators.Inner | SupportedJoinOperators.LeftOuter | SupportedJoinOperators.RightOuter | SupportedJoinOperators.FullOuter
}
}
};

private static DataTable GetRestrictions() =>
new(DbMetaDataCollectionNames.Restrictions)
{
Expand Down
25 changes: 25 additions & 0 deletions DuckDB.NET.Test/SchemaTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,31 @@ public void IndexesTooManyRestrictions()
Assert.Throws<ArgumentException>(() => Connection.GetSchema("Indexes", new string [5]));
}

[Fact]
public void DataSourceInformation() {
var schema = Connection.GetSchema(DbMetaDataCollectionNames.DataSourceInformation);
Assert.NotEmpty(schema.Rows);

Assert.Equal(1, schema.Rows.Count);
Assert.Equal("\\.", schema.Rows[0][DbMetaDataColumnNames.CompositeIdentifierSeparatorPattern]);
Assert.Equal("duckdb", schema.Rows[0][DbMetaDataColumnNames.DataSourceProductName]);
Assert.Equal(Connection.ServerVersion, schema.Rows[0][DbMetaDataColumnNames.DataSourceProductVersion]);
Assert.Equal(Connection.ServerVersion, schema.Rows[0][DbMetaDataColumnNames.DataSourceProductVersionNormalized]);
Assert.Equal(GroupByBehavior.Unrelated, (GroupByBehavior)schema.Rows[0][DbMetaDataColumnNames.GroupByBehavior]);
Assert.Equal("(^\\[\\p{Lo}\\p{Lu}\\p{Ll}_@#][\\p{Lo}\\p{Lu}\\p{Ll}\\p{Nd}@$#_]*$)|(^\\[[^\\]\\0]|\\]\\]+\\]$)|(^\\\"[^\\\"\\0]|\\\"\\\"+\\\"$)", schema.Rows[0][DbMetaDataColumnNames.IdentifierPattern]);
Assert.Equal(IdentifierCase.Insensitive, (IdentifierCase)schema.Rows[0][DbMetaDataColumnNames.IdentifierCase]);
Assert.Equal(false, schema.Rows[0][DbMetaDataColumnNames.OrderByColumnsInSelect]);
Assert.Equal("{0}", schema.Rows[0][DbMetaDataColumnNames.ParameterMarkerFormat]);
Assert.Equal("$[\\p{Lo}\\p{Lu}\\p{Ll}\\p{Lm}_@#][\\p{Lo}\\p{Lu}\\p{Ll}\\p{Lm}\\p{Nd}\\uff3f_@#\\$]*(?=\\s+|$)", schema.Rows[0][DbMetaDataColumnNames.ParameterMarkerPattern]);
Assert.Equal(128, schema.Rows[0][DbMetaDataColumnNames.ParameterNameMaxLength]);
Assert.Equal("^[\\p{Lo}\\p{Lu}\\p{Ll}\\p{Lm}_@#][\\p{Lo}\\p{Lu}\\p{Ll}\\p{Lm}\\p{Nd}\\uff3f_@#\\$]*(?=\\s+|$)", schema.Rows[0][DbMetaDataColumnNames.ParameterNamePattern]);
Assert.Equal("(([^\\[]|\\]\\])*)", schema.Rows[0][DbMetaDataColumnNames.QuotedIdentifierPattern]);
Assert.Equal(IdentifierCase.Insensitive, (IdentifierCase)schema.Rows[0][DbMetaDataColumnNames.QuotedIdentifierCase]);
Assert.Equal(";", schema.Rows[0][DbMetaDataColumnNames.StatementSeparatorPattern]);
Assert.Equal("'(([^']|'')*)'", schema.Rows[0][DbMetaDataColumnNames.StringLiteralPattern]);
Assert.Equal(SupportedJoinOperators.Inner | SupportedJoinOperators.LeftOuter | SupportedJoinOperators.RightOuter | SupportedJoinOperators.FullOuter, (SupportedJoinOperators)schema.Rows[0][DbMetaDataColumnNames.SupportedJoinOperators]);
}

private static IEnumerable<string> GetValues(DataTable schema, string columnName) =>
schema.Rows.Cast<DataRow>().Select(r => (string)r[columnName]);
}
Loading