This is an automated email from the ASF dual-hosted git repository.

curth pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git


The following commit(s) were added to refs/heads/main by this push:
     new 43ee3aa02 feat(csharp/src/Drivers/Apache): improve type name handling 
for CHAR/VARCHAR/DECIMAL (#1896)
43ee3aa02 is described below

commit 43ee3aa02cc4a77b1551311396e3a88a32fb7b96
Author: Bruce Irschick <[email protected]>
AuthorDate: Tue Jun 4 10:30:10 2024 -0700

    feat(csharp/src/Drivers/Apache): improve type name handling for 
CHAR/VARCHAR/DECIMAL (#1896)
    
    The native response from Spark/Databricks for the type name in the
    column metadata (which is used to populate the `XdbcTypeName` column in
    the `GetObjects` call) includes both the base type and the precision and
    scale clause for DECIMAL/CHAR/VARCHAR. For example, `DECIMAL(38,2)`,
    `CHAR(255)`, `VARCHAR(255)`, etc.
    
    This change removes the trailing precision and scale clause `( precision
    [ , scale ] )` from returned value for `XdbcTypeName`. As well, the
    `XdbcColumnSize` is now being populated with the maximum precision of
    `VARCHAR` and the fixed length of `CHAR` types.
    
    Examples:
    
    | Native Type Name| XdbcTypeName | XdbcColumnSize | XdbcDecimalDigits |
    | ------------- | ------------- | ------------- | ------------- |
    | VARCHAR(255) | VARCHAR | 255 | `null` |
    | CHAR(255) | CHAR | 255 | `null` |
    | DECIMAL(38,2) | DECIMAL | 38 | 2 |
    | DECIMAL(38) | DECIMAL | 38 | 0 |
    | DECIMAL | DECIMAL | 10 | 0 |
    | STRING | STRING | 2147483647 | `null` |
---
 csharp/src/Drivers/Apache/Spark/SparkConnection.cs | 107 ++++------
 .../src/Drivers/Apache/Spark/SqlTypeNameParser.cs  | 227 +++++++++++++++++++++
 csharp/test/Drivers/Apache/Spark/DriverTests.cs    |  30 ++-
 csharp/test/Drivers/Apache/Spark/StatementTests.cs |   2 +-
 4 files changed, 290 insertions(+), 76 deletions(-)

diff --git a/csharp/src/Drivers/Apache/Spark/SparkConnection.cs 
b/csharp/src/Drivers/Apache/Spark/SparkConnection.cs
index 33a65f0a8..798fdeec2 100644
--- a/csharp/src/Drivers/Apache/Spark/SparkConnection.cs
+++ b/csharp/src/Drivers/Apache/Spark/SparkConnection.cs
@@ -54,8 +54,6 @@ namespace Apache.Arrow.Adbc.Drivers.Apache.Spark
         const string InfoDriverName = "ADBC Spark Driver";
         const string InfoDriverArrowVersion = "1.0.0";
         const bool InfoVendorSql = true;
-        const int DecimalPrecisionDefault = 10;
-        const int DecimalScaleDefault = 0;
         const string ColumnDef = "COLUMN_DEF";
         const string ColumnName = "COLUMN_NAME";
         const string DataType = "DATA_TYPE";
@@ -154,7 +152,7 @@ namespace Apache.Arrow.Adbc.Drivers.Apache.Spark
             /// </summary>
             NCHAR = -15,
             /// <summary>
-            /// identifies the generic SQL value NULL
+            /// identifies the generic SQL type NULL
             /// </summary>
             NULL = 0,
             /// <summary>
@@ -660,12 +658,11 @@ namespace Apache.Arrow.Adbc.Drivers.Apache.Spark
                     tableInfo?.ColumnName.Add(columnName);
                     tableInfo?.ColType.Add(colType);
                     tableInfo?.Nullable.Add(nullable);
-                    tableInfo?.TypeName.Add(typeName);
                     tableInfo?.IsAutoIncrement.Add(isAutoIncrement);
                     tableInfo?.IsNullable.Add(isNullable);
                     tableInfo?.ColumnDefault.Add(columnDefault);
                     tableInfo?.OrdinalPosition.Add(ordinalPos);
-                    SetPrecisionAndScale(colType, typeName, tableInfo);
+                    SetPrecisionScaleAndTypeName(colType, typeName, tableInfo);
                 }
             }
 
@@ -702,22 +699,47 @@ namespace Apache.Arrow.Adbc.Drivers.Apache.Spark
             .Select(t => new { Index = t.Position - 1, t.ColumnName })
             .ToDictionary(t => t.ColumnName, t => t.Index);
 
-        private static void SetPrecisionAndScale(short colType, string 
typeName, TableInfo? tableInfo)
+        private static void SetPrecisionScaleAndTypeName(short colType, string 
typeName, TableInfo? tableInfo)
         {
+            // Keep the original type name
+            tableInfo?.TypeName.Add(typeName);
             switch (colType)
             {
                 case (short)ColumnTypeId.DECIMAL:
                 case (short)ColumnTypeId.NUMERIC:
                     {
-                        Decimal128Type decimalType = 
SqlDecimalTypeParser.ParseOrDefault(typeName, new 
Decimal128Type(DecimalPrecisionDefault, DecimalScaleDefault));
-                        tableInfo?.Precision.Add(decimalType.Precision);
-                        tableInfo?.Scale.Add((short)decimalType.Scale);
+                        SqlDecimalParserResult result = new 
SqlDecimalTypeParser().ParseOrDefault(typeName, new 
SqlDecimalParserResult(typeName));
+                        tableInfo?.Precision.Add(result.Precision);
+                        tableInfo?.Scale.Add((short)result.Scale);
+                        tableInfo?.BaseTypeName.Add(result.BaseTypeName);
+                        break;
+                    }
+
+                case (short)ColumnTypeId.CHAR:
+                case (short)ColumnTypeId.NCHAR:
+                    {
+                        bool success = new 
SqlCharTypeParser().TryParse(typeName, out SqlCharVarcharParserResult? result);
+                        tableInfo?.Precision.Add(success ? result!.ColumnSize 
: SqlVarcharTypeParser.VarcharColumnSizeDefault);
+                        tableInfo?.Scale.Add(null);
+                        tableInfo?.BaseTypeName.Add(success ? 
result!.BaseTypeName : "CHAR");
+                        break;
+                    }
+                case (short)ColumnTypeId.VARCHAR:
+                case (short)ColumnTypeId.LONGVARCHAR:
+                case (short)ColumnTypeId.LONGNVARCHAR:
+                case (short)ColumnTypeId.NVARCHAR:
+                    {
+                        bool success = new 
SqlVarcharTypeParser().TryParse(typeName, out SqlCharVarcharParserResult? 
result);
+                        tableInfo?.Precision.Add(success ? result!.ColumnSize 
: SqlVarcharTypeParser.VarcharColumnSizeDefault);
+                        tableInfo?.Scale.Add(null);
+                        tableInfo?.BaseTypeName.Add(success ? 
result!.BaseTypeName : "STRING");
                         break;
                     }
 
                 default:
                     tableInfo?.Precision.Add(null);
                     tableInfo?.Scale.Add(null);
+                    tableInfo?.BaseTypeName.Add(typeName);
                     break;
             }
         }
@@ -761,7 +783,9 @@ namespace Apache.Arrow.Adbc.Drivers.Apache.Spark
                 case (int)ColumnTypeId.NUMERIC:
                     // Note: parsing the type name for SQL DECIMAL types as 
the precision and scale values
                     // are not returned in the Thrift call to GetColumns
-                    return SqlDecimalTypeParser.ParseOrDefault(typeName, new 
Decimal128Type(DecimalPrecisionDefault, DecimalScaleDefault));
+                    return new SqlDecimalTypeParser()
+                        .ParseOrDefault(typeName, new 
SqlDecimalParserResult(typeName))
+                        .Decimal128Type;
                 case (int)ColumnTypeId.NULL:
                     return NullType.Default;
                 case (int)ColumnTypeId.ARRAY:
@@ -897,11 +921,13 @@ namespace Apache.Arrow.Adbc.Drivers.Apache.Spark
             {
                 columnNameBuilder.Append(tableInfo.ColumnName[i]);
                 ordinalPositionBuilder.Append(tableInfo.OrdinalPosition[i]);
-                remarksBuilder.Append("");
+                // Use the "remarks" field to store the original type name 
value
+                remarksBuilder.Append(tableInfo.TypeName[i]);
                 xdbcColumnSizeBuilder.Append(tableInfo.Precision[i]);
                 xdbcDecimalDigitsBuilder.Append(tableInfo.Scale[i]);
                 xdbcDataTypeBuilder.Append(tableInfo.ColType[i]);
-                xdbcTypeNameBuilder.Append(tableInfo.TypeName[i]);
+                // Just the base type name without precision or scale clause
+                xdbcTypeNameBuilder.Append(tableInfo.BaseTypeName[i]);
                 xdbcNumPrecRadixBuilder.AppendNull();
                 xdbcNullableBuilder.Append(tableInfo.Nullable[i]);
                 xdbcColumnDefBuilder.Append(tableInfo.ColumnDefault[i]);
@@ -963,61 +989,6 @@ namespace Apache.Arrow.Adbc.Drivers.Apache.Spark
             return builder.ToString();
         }
 
-        /// <summary>
-        /// Provides a parser for SQL DECIMAL type definitions.
-        /// </summary>
-        private static class SqlDecimalTypeParser
-        {
-            // Pattern is based on this definition
-            // 
https://docs.databricks.com/en/sql/language-manual/data-types/decimal-type.html#syntax
-            // { DECIMAL | DEC | NUMERIC } [ (  p [ , s ] ) ]
-            // p: Optional maximum precision (total number of digits) of the 
number between 1 and 38. The default is 10.
-            // s: Optional scale of the number between 0 and p. The number of 
digits to the right of the decimal point. The default is 0.
-            private static readonly Regex s_expression = new(
-                
@"^\s*(?<typeName>((DECIMAL)|(DEC)|(NUMERIC)))(\s*\(\s*((?<precision>\d{1,2})(\s*\,\s*(?<scale>\d{1,2}))?)\s*\))?\s*$",
-                RegexOptions.IgnoreCase | RegexOptions.Compiled | 
RegexOptions.CultureInvariant);
-
-            /// <summary>
-            /// Parses the input string for a valid SQL DECIMAL type 
definition and returns a new <see cref="Decimal128Type"/> or returns the 
<c>defaultValue</c>, if invalid.
-            /// </summary>
-            /// <param name="input">The SQL type defintion string to 
parse.</param>
-            /// <param name="defaultValue">If input string is an invalid SQL 
DECIMAL type definition, this value is returned instead.</param>
-            /// <returns>If input string is a valid SQL DECIMAL type 
definition, it returns a new <see cref="Decimal128Type"/>; otherwise 
<c>defaultValue</c>.</returns>
-            public static Decimal128Type ParseOrDefault(string input, 
Decimal128Type defaultValue)
-            {
-                return TryParse(input, out Decimal128Type? candidate) ? 
candidate! : defaultValue;
-            }
-
-            /// <summary>
-            /// Tries to parse the input string for a valid SQL DECIMAL type 
definition.
-            /// </summary>
-            /// <param name="input">The SQL type defintion string to 
parse.</param>
-            /// <param name="value">If successful, an new <see 
cref="Decimal128Type"/> with the precision and scale set; otherwise 
<c>null</c>.</param>
-            /// <returns>True if it can successfully parse the type definition 
input string; otherwise false.</returns>
-            private static bool TryParse(string input, out Decimal128Type? 
value)
-            {
-                // Ensure defaults are set, in case not provided in 
precision/scale clause.
-                int precision = DecimalPrecisionDefault;
-                int scale = DecimalScaleDefault;
-
-                Match match = s_expression.Match(input);
-                if (!match.Success)
-                {
-                    value = null;
-                    return false;
-                }
-
-                GroupCollection groups = match.Groups;
-                Group precisionGroup = groups["precision"];
-                Group scaleGroup = groups["scale"];
-
-                precision = precisionGroup.Success && 
int.TryParse(precisionGroup.Value, out int candidatePrecision) ? 
candidatePrecision : precision;
-                scale = scaleGroup.Success && int.TryParse(scaleGroup.Value, 
out int candidateScale) ? candidateScale : scale;
-
-                value = new Decimal128Type(precision, scale);
-                return true;
-            }
-        }
 
         private string GetProductVersion()
         {
@@ -1034,6 +1005,8 @@ namespace Apache.Arrow.Adbc.Drivers.Apache.Spark
 
         public List<short> ColType { get; } = new();
 
+        public List<string> BaseTypeName { get; } = new();
+
         public List<string> TypeName { get; } = new();
 
         public List<short> Nullable { get; } = new();
diff --git a/csharp/src/Drivers/Apache/Spark/SqlTypeNameParser.cs 
b/csharp/src/Drivers/Apache/Spark/SqlTypeNameParser.cs
new file mode 100644
index 000000000..915fb1a19
--- /dev/null
+++ b/csharp/src/Drivers/Apache/Spark/SqlTypeNameParser.cs
@@ -0,0 +1,227 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*    http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Text.RegularExpressions;
+using Apache.Arrow.Types;
+
+namespace Apache.Arrow.Adbc.Drivers.Apache.Spark
+{
+    /// <summary>
+    /// Abstract and generic SQL data type name parser.
+    /// </summary>
+    /// <typeparam name="T">The <see cref="ParserResult"/> type when returning 
a successful parse</typeparam>
+    internal abstract class SqlTypeNameParser<T> where T : ParserResult
+    {
+        /// <summary>
+        /// Gets the <see cref="Regex"/> expression to parse the SQL type name
+        /// </summary>
+        public abstract Regex Expression { get; }
+
+        /// <summary>
+        /// Generates the successful result of a matching parse
+        /// </summary>
+        /// <param name="input">The original SQL type name</param>
+        /// <param name="match">The successful <see cref="Match"/> 
result</param>
+        /// <returns></returns>
+        public abstract T GenerateResult(string input, Match match);
+
+        /// <summary>
+        /// Tries to parse the input string for a valid SQL type definition.
+        /// </summary>
+        /// <param name="input">The SQL type defintion string to parse.</param>
+        /// <param name="result">If successful, the result; otherwise 
<c>null</c>.</param>
+        /// <returns>True if it can successfully parse the type definition 
input string; otherwise false.</returns>
+        public bool TryParse(string input, out T? result)
+        {
+            Match match = Expression.Match(input);
+            if (!match.Success)
+            {
+                result = default;
+                return false;
+            }
+
+            result = GenerateResult(input, match);
+            return match.Success;
+        }
+
+        /// <summary>
+        /// Parses the input string for a valid SQL type definition and 
returns the result or returns the <c>defaultValue</c>, if invalid.
+        /// </summary>
+        /// <param name="input">The SQL type defintion string to parse.</param>
+        /// <param name="defaultValue">If input string is an invalid type 
definition, this result is returned instead.</param>
+        /// <returns>If input string is a valid SQL type definition, it 
returns the result; otherwise <c>defaultValue</c>.</returns>
+        public T ParseOrDefault(string input, T defaultValue)
+        {
+            return TryParse(input, out T? result) ? result! : defaultValue;
+        }
+    }
+
+    /// <summary>
+    /// An result for parsing a SQL data type.
+    /// </summary>
+    /// <param name="typeName">The original SQL type name to parse</param>
+    /// <param name="baseTypeName">The 'base' type name to use which is 
typically more simple without sub-clauses</param>
+    internal class ParserResult(string typeName, string baseTypeName)
+    {
+        /// <summary>
+        /// The original SQL type name
+        /// </summary>
+        public string TypeName { get; } = typeName;
+
+        /// <summary>
+        /// The 'base' type name to use which is typically more simple without 
sub-clauses
+        /// </summary>
+        public string BaseTypeName { get; } = baseTypeName;
+    }
+
+    /// <summary>
+    /// An result for parsing the SQL 
CHAR/NCHAR/STRING/VARCHAR/NVARCHAR/LONGVARCHAR/LONGNVARCHAR data types.
+    /// </summary>
+    /// <param name="typeName">The original SQL type name to parse</param>
+    /// <param name="baseTypeName">The 'base' type name without the length 
clause</param>
+    /// <param name="columnSize">The length of the column for this type 
name</param>
+    internal class SqlCharVarcharParserResult(string typeName, string 
baseTypeName, int columnSize) : ParserResult(typeName, baseTypeName)
+    {
+        /// <summary>
+        /// The length of the column for this type name
+        /// </summary>
+        public int ColumnSize { get; } = columnSize;
+    }
+
+    /// <summary>
+    /// An result for parsing the SQL DECIMAL/DEC/NUMERIC data types.
+    /// </summary>
+    /// <param name="typeName">The original SQL type name to parse</param>
+    /// <param name="baseTypeName">The 'base' type name without the precision 
or scale clause</param>
+    /// <param name="precision">The precision of the decimal type</param>
+    /// <param name="scale">The scale (decimal digits) of the decimal 
type</param>
+    internal class SqlDecimalParserResult(string typeName, string 
baseTypeName, int precision, int scale) : ParserResult(typeName, baseTypeName)
+    {
+        /// <summary>
+        /// Constructs a new default result given the original type name.
+        /// </summary>
+        /// <param name="typeName">The original SQL type name to parse</param>
+        public SqlDecimalParserResult(string typeName) : this(typeName, 
"DECIMAL", SqlDecimalTypeParser.DecimalPrecisionDefault, 
SqlDecimalTypeParser.DecimalScaleDefault) { }
+
+        /// <summary>
+        /// The precision of the decimal type
+        /// </summary>
+        public int Precision { get; } = precision;
+
+        /// <summary>
+        /// The scale (decimal digits) of the decimal type
+        /// </summary>
+        public int Scale { get; } = scale;
+
+        /// <summary>
+        /// The <see cref='Types.Decimal128Type'/> representing the parsed 
type name
+        /// </summary>
+        public Decimal128Type Decimal128Type { get; } = new 
Decimal128Type(precision, scale);
+    }
+
+    /// <summary>
+    /// Provides a parser for CHAR type definitions.
+    /// </summary>
+    internal class SqlCharTypeParser : 
SqlTypeNameParser<SqlCharVarcharParserResult>
+    {
+        private const string BaseTypeName = "CHAR";
+
+        private static readonly Regex s_expression = new(
+            
@"^\s*(?<typeName>((CHAR)|(NCHAR)))(\s*\(\s*(?<precision>\d{1,10})\s*\))\s*$",
+            RegexOptions.IgnoreCase | RegexOptions.Compiled | 
RegexOptions.CultureInvariant);
+
+        public override Regex Expression => s_expression;
+
+        public override SqlCharVarcharParserResult GenerateResult(string 
input, Match match)
+        {
+            GroupCollection groups = match.Groups;
+            Group precisionGroup = groups["precision"];
+
+            int precision = int.TryParse(precisionGroup.Value, out int 
candidatePrecision)
+                ? candidatePrecision
+                : throw new ArgumentException($"Unable to parse length: 
'{precisionGroup.Value}'", nameof(input));
+            return new SqlCharVarcharParserResult(input, BaseTypeName, 
precision);
+        }
+    }
+
+    /// <summary>
+    /// Provides a parser for SQL VARCHAR/STRING type definitions.
+    /// </summary>
+    internal class SqlVarcharTypeParser : 
SqlTypeNameParser<SqlCharVarcharParserResult>
+    {
+        internal const int VarcharColumnSizeDefault = int.MaxValue;
+
+        private const string VarcharBaseTypeName = "VARCHAR";
+        private const string StringBaseTypeName = "STRING";
+
+        private static readonly Regex s_expression = new(
+            
@"^\s*(?<typeName>((STRING)|(VARCHAR)|(LONGVARCHAR)|(LONGNVARCHAR)|(NVARCHAR)))(\s*\(\s*(?<precision>\d{1,10})\s*\))?\s*$",
+            RegexOptions.IgnoreCase | RegexOptions.Compiled | 
RegexOptions.CultureInvariant);
+
+        public override Regex Expression => s_expression;
+
+        public override SqlCharVarcharParserResult GenerateResult(string 
input, Match match)
+        {
+            GroupCollection groups = match.Groups;
+            Group precisionGroup = groups["precision"];
+            Group typeNameGroup = groups["typeName"];
+
+            string baseTypeName = 
typeNameGroup.Value.Equals(StringBaseTypeName, 
StringComparison.InvariantCultureIgnoreCase)
+                ? StringBaseTypeName
+                : VarcharBaseTypeName;
+            int precision = precisionGroup.Success && 
int.TryParse(precisionGroup.Value, out int candidatePrecision)
+                ? candidatePrecision
+                : VarcharColumnSizeDefault;
+            return new SqlCharVarcharParserResult(input, baseTypeName, 
precision);
+        }
+    }
+
+    /// <summary>
+    /// Provides a parser for SQL DECIMAL type definitions.
+    /// </summary>
+    internal class SqlDecimalTypeParser : 
SqlTypeNameParser<SqlDecimalParserResult>
+    {
+        internal const int DecimalPrecisionDefault = 10;
+        internal const int DecimalScaleDefault = 0;
+
+        private const string BaseTypeName = "DECIMAL";
+
+        // Pattern is based on this definition
+        // 
https://docs.databricks.com/en/sql/language-manual/data-types/decimal-type.html#syntax
+        // { DECIMAL | DEC | NUMERIC } [ (  p [ , s ] ) ]
+        // p: Optional maximum result (total number of digits) of the number 
between 1 and 38. The default is 10.
+        // s: Optional scale of the number between 0 and p. The number of 
digits to the right of the decimal point. The default is 0.
+        private static readonly Regex s_expression = new(
+            
@"^\s*(?<typeName>((DECIMAL)|(DEC)|(NUMERIC)))(\s*\(\s*((?<precision>\d{1,2})(\s*\,\s*(?<scale>\d{1,2}))?)\s*\))?\s*$",
+            RegexOptions.IgnoreCase | RegexOptions.Compiled | 
RegexOptions.CultureInvariant);
+
+        public override Regex Expression => s_expression;
+
+        public override SqlDecimalParserResult GenerateResult(string input, 
Match match)
+        {
+            GroupCollection groups = match.Groups;
+            Group precisionGroup = groups["precision"];
+            Group scaleGroup = groups["scale"];
+
+            int precision = precisionGroup.Success && 
int.TryParse(precisionGroup.Value, out int candidatePrecision) ? 
candidatePrecision : DecimalPrecisionDefault;
+            int scale = scaleGroup.Success && int.TryParse(scaleGroup.Value, 
out int candidateScale) ? candidateScale : DecimalScaleDefault;
+
+            return new SqlDecimalParserResult(input, BaseTypeName, precision, 
scale);
+        }
+    }
+}
diff --git a/csharp/test/Drivers/Apache/Spark/DriverTests.cs 
b/csharp/test/Drivers/Apache/Spark/DriverTests.cs
index 822dae2e0..8fb341f87 100644
--- a/csharp/test/Drivers/Apache/Spark/DriverTests.cs
+++ b/csharp/test/Drivers/Apache/Spark/DriverTests.cs
@@ -351,19 +351,33 @@ namespace Apache.Arrow.Adbc.Tests.Drivers.Apache.Spark
                 Assert.False(string.IsNullOrEmpty(column.Name));
                 Assert.False(string.IsNullOrEmpty(column.XdbcTypeName));
 
-                var types = 
Enum.GetValues(typeof(SupportedSparkDataType)).Cast<SupportedSparkDataType>();
-                
Assert.Contains((SupportedSparkDataType)column.XdbcSqlDataType!, types);
+                var supportedTypes = 
Enum.GetValues(typeof(SupportedSparkDataType)).Cast<SupportedSparkDataType>();
+                
Assert.Contains((SupportedSparkDataType)column.XdbcSqlDataType!, 
supportedTypes);
                 Assert.Equal(column.XdbcDataType, column.XdbcSqlDataType);
 
                 Assert.NotNull(column.XdbcDataType);
-                Assert.Contains((SupportedSparkDataType)column.XdbcDataType!, 
types);
+                Assert.Contains((SupportedSparkDataType)column.XdbcDataType!, 
supportedTypes);
 
-                bool isDecimalType = column.XdbcDataType == 
(short)SupportedSparkDataType.DECIMAL || column.XdbcDataType == 
(short)SupportedSparkDataType.NUMERIC;
-                Assert.Equal(column.XdbcColumnSize.HasValue, isDecimalType);
-                Assert.Equal(column.XdbcDecimalDigits.HasValue, isDecimalType);
+                HashSet<short> typesHaveColumnSize = new()
+                {
+                    (short)SupportedSparkDataType.DECIMAL,
+                    (short)SupportedSparkDataType.NUMERIC,
+                    (short)SupportedSparkDataType.CHAR,
+                    (short)SupportedSparkDataType.VARCHAR,
+                };
+                HashSet<short> typesHaveDecimalDigits = new()
+                {
+                    (short)SupportedSparkDataType.DECIMAL,
+                    (short)SupportedSparkDataType.NUMERIC,
+                };
+
+                bool typeHasColumnSize = 
typesHaveColumnSize.Contains(column.XdbcDataType.Value);
+                Assert.Equal(column.XdbcColumnSize.HasValue, 
typeHasColumnSize);
+
+                bool typeHasDecimalDigits = 
typesHaveDecimalDigits.Contains(column.XdbcDataType.Value);
+                Assert.Equal(column.XdbcDecimalDigits.HasValue, 
typeHasDecimalDigits);
 
-                Assert.NotNull(column.Remarks);
-                Assert.True(string.IsNullOrEmpty(column.Remarks));
+                Assert.False(string.IsNullOrEmpty(column.Remarks));
 
                 Assert.NotNull(column.XdbcColumnDef);
 
diff --git a/csharp/test/Drivers/Apache/Spark/StatementTests.cs 
b/csharp/test/Drivers/Apache/Spark/StatementTests.cs
index 6a1e4c00a..e1e44e59f 100644
--- a/csharp/test/Drivers/Apache/Spark/StatementTests.cs
+++ b/csharp/test/Drivers/Apache/Spark/StatementTests.cs
@@ -35,7 +35,7 @@ namespace Apache.Arrow.Adbc.Tests.Drivers.Apache.Spark
     [TestCaseOrderer("Apache.Arrow.Adbc.Tests.Xunit.TestOrderer", 
"Apache.Arrow.Adbc.Tests")]
     public class StatementTests : SparkTestBase
     {
-        private static List<string> DefaultTableTypes => new() { "BASE TABLE", 
"VIEW" };
+        private static List<string> DefaultTableTypes => new() { "TABLE", 
"VIEW" };
 
         public StatementTests(ITestOutputHelper? outputHelper) : 
base(outputHelper)
         {

Reply via email to