diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlMetaDataFactory.ReservedWords.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlMetaDataFactory.ReservedWords.cs
new file mode 100644
index 0000000000..73b85f5d45
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlMetaDataFactory.ReservedWords.cs
@@ -0,0 +1,177 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Data;
+using System.Data.Common;
+
+#nullable enable
+
+namespace Microsoft.Data.SqlClient;
+
+internal sealed partial class SqlMetaDataFactory
+{
+ ///
+ /// Adds reserved words to the indicated metadata DataSet.
+ ///
+ /// The metadata DataSet to contain the reserved words.
+ ///
+ /// These reserved words are defined by the server, and vary depending upon the version
+ /// and edition.
+ ///
+ ///
+ private static void LoadReservedWordsDataTables(DataSet metaDataCollectionsDataSet)
+ {
+ DataTable reservedWordsDataTable = CreateReservedWordsDataTable();
+
+ reservedWordsDataTable.BeginLoadData();
+
+ // @TODO: These have been ported from the existing XML resource file, but they don't perfectly
+ // align with the referenced link. These need to be reviewed, and if it's correct to add
+ // the new keywords then they need to indicate which version of SQL Server introduced them.
+ // @TODO: Azure Synapse Analytics also has an extra reserved keyword. This isn't included at
+ // the moment, but if we choose to do so then we need a way to identify such. Doing so may
+ // be non-trivial, depending upon whether we query SERVERPROPERTY('EngineEdition') or use a
+ // similar approach to ADP.IsAzureSynapseOnDemandEndpoint (i.e. check the data source string.)
+
+ // Add reserved keywords used by SQL Server and Azure Synapse Analytics.
+ AddReservedWords(minVersion: null, maxVersion: null,
+ "ADD", "ALL", "ALTER", "AND", "ANY", "AS", "ASC", "AUTHORIZATION", "BACKUP",
+ "BEGIN", "BETWEEN", "BREAK", "BROWSE", "BULK", "BY", "CASCADE", "CASE", "CHECK",
+ "CHECKPOINT", "CLOSE", "CLUSTERED", "COALESCE", "COLLATE", "COLUMN", "COMMIT", "COMPUTE", "CONSTRAINT",
+ "CONTAINS", "CONTAINSTABLE", "CONTINUE", "CONVERT", "CREATE", "CROSS", "CURRENT", "CURRENT_DATE", "CURRENT_TIME",
+ "CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", "DATABASE", "DBCC", "DEALLOCATE", "DECLARE", "DEFAULT", "DELETE",
+ "DENY", "DESC", "DISK", "DISTINCT", "DISTRIBUTED", "DOUBLE", "DROP", "DUMP", "ELSE",
+ "END", "ERRLVL", "ESCAPE", "EXCEPT", "EXEC", "EXECUTE", "EXISTS", "EXIT", "EXTERNAL",
+ "FETCH", "FILE", "FILLFACTOR", "FOR", "FOREIGN", "FREETEXT", "FREETEXTTABLE", "FROM", "FULL",
+ "FUNCTION", "GOTO", "GRANT", "GROUP", "HAVING", "HOLDLOCK", "IDENTITY", "IDENTITY_INSERT", "IDENTITYCOL",
+ "IF", "IN", "INDEX", "INNER", "INSERT", "INTERSECT", "INTO", "IS", "JOIN",
+ // @TODO: Missing keyword: MERGE
+ "KEY", "KILL", "LEFT", "LIKE", "LINENO", "LOAD", /* "MERGE", */ "NATIONAL", "NOCHECK",
+ "NONCLUSTERED", "NOT", "NULL", "NULLIF", "OF", "OFF", "OFFSETS", "ON", "OPEN",
+ "OPENDATASOURCE", "OPENQUERY", "OPENROWSET", "OPENXML", "OPTION", "OR", "ORDER", "OUTER", "OVER",
+ // @TODO: Missing keyword: PIVOT
+ "PERCENT", /* "PIVOT", */ "PLAN", "PRECISION", "PRIMARY", "PRINT", "PROC", "PROCEDURE", "PUBLIC",
+ "RAISERROR", "READ", "READTEXT", "RECONFIGURE", "REFERENCES", "REPLICATION", "RESTORE", "RESTRICT", "RETURN",
+ // @TODO: Missing keyword: REVERT
+ /* "REVERT", */ "REVOKE", "RIGHT", "ROLLBACK", "ROWCOUNT", "ROWGUIDCOL", "RULE", "SAVE", "SCHEMA",
+ // @TODO: Missing keywords: SECURITYAUDIT, SEMANTICKEYPHRASETABLE, SEMANTICSIMILARITYDETAILSTABLE
+ /* "SECURITYAUDIT", */ "SELECT", /* "SEMANTICKEYPHRASETABLE", "SEMANTICSIMILARITYDETAILSTABLE", */
+ // @TODO: Missing keyword: SEMANTICSIMILARITYTABLE
+ /* "SEMANTICSIMILARITYTABLE", */ "SESSION_USER", "SET", "SETUSER", "SHUTDOWN",
+ // @TODO: Missing keyword: TABLESAMPLE
+ "SOME", "STATISTICS", "SYSTEM_USER", "TABLE", /* "TABLESAMPLE", */ "TEXTSIZE", "THEN", "TO", "TOP",
+ // @TODO: Missing keywords: TRY_CONVERT, UNPIVOT
+ "TRAN", "TRANSACTION", "TRIGGER", "TRUNCATE", /* "TRY_CONVERT", */ "TSEQUAL", "UNION", "UNIQUE", /* "UNPIVOT", */
+ "UPDATE", "UPDATETEXT", "USE", "USER", "VALUES", "VARYING", "VIEW", "WAITFOR", "WHEN",
+ // @TODO: Missing keyword: WITHIN GROUP
+ "WHERE", "WHILE", "WITH", /* "WITHIN GROUP", */ "WRITETEXT");
+
+ // Add ODBC reserved keywords. Some of these overlap with the previous category, and are not included.
+ AddReservedWords(minVersion: null, maxVersion: null,
+ "ABSOLUTE", "ACTION", "ADA", "ALLOCATE", "ARE", "ASSERTION", "AT", "AVG", "BIT",
+ "BIT_LENGTH", "BOTH", "CASCADED", "CAST", "CATALOG", "CHAR", "CHAR_LENGTH", "CHARACTER", "CHARACTER_LENGTH",
+ "COLLATION", "CONNECT", "CONNECTION", "CONSTRAINTS", "CORRESPONDING", "COUNT", "DATE", "DAY", "DECIMAL",
+ "DEFERRABLE", "DEFERRED", "DESCRIBE", "DESCRIPTOR", "DIAGNOSTICS", "DISCONNECT", "DOMAIN", "END-EXEC", "EXCEPTION",
+ "EXTRACT", "FALSE", "FIRST", "FLOAT", "FORTRAN", "FOUND", "GET", "GLOBAL", "GO",
+ "HOUR", "IMMEDIATE", "INCLUDE", "INDICATOR", "INITIALLY", "INPUT", "INSENSITIVE", "INT", "INTEGER",
+ "INTERVAL", "ISOLATION", "LANGUAGE", "LAST", "LEADING", "LEVEL", "LOCAL", "LOWER", "MATCH",
+ "MAX", "MIN", "MINUTE", "MODULE", "MONTH", "NAMES", "NATURAL", "NCHAR", "NEXT",
+ "NO", "NONE", "NUMERIC", "OCTET_LENGTH", "ONLY", "OUTPUT", "OVERLAPS", "PAD", "PASCAL",
+ "POSITION", "PREPARE", "PRESERVE", "PRIOR", "PRIVILEGES", "REAL", "RELATIVE", "ROWS", "SCROLL",
+ "SECOND", "SECTION", "SESSION", "SIZE", "SMALLINT", "SPACE", "SQL", "SQLCA", "SQLCODE",
+ "SQLERROR", "SQLSTATE", "SQLWARNING", "SUBSTRING", "SUM", "TEMPORARY", "TIME", "TIMESTAMP", "TIMEZONE_HOUR",
+ "TIMEZONE_MINUTE", "TRAILING", "TRANSLATE", "TRANSLATION", "TRIM", "TRUE", "UNKNOWN", "UPPER", "USAGE",
+ "USING", "VALUE", "VARCHAR", "WHENEVER", "WORK", "WRITE", "YEAR", "ZONE");
+
+ // Add future reserved keywords.
+ AddReservedWords(minVersion: null, maxVersion: null,
+ // @TODO: Missing keywords: ASENSITIVE, ASYMMETRIC, ATOMIC
+ "ADMIN", "AFTER", "AGGREGATE", "ALIAS", "ARRAY", /* "ASENSITIVE", "ASYMMETRIC", "ATOMIC", */ "BEFORE",
+ // @TODO: Missing keyword: CALLED, CARDINALITY
+ "BINARY", "BLOB", "BOOLEAN", "BREADTH", "CALL", /* "CALLED", "CARDINALITY", */ "CLASS", "CLOB",
+ // @TODO: Missing keywords: COLLECT, CONDITION, CORR, COVAR_POP, COVAR_SAMP, CUME_DIST
+ /* "COLLECT", */ "COMPLETION", /* "CONDITION", */ "CONSTRUCTOR", /* "CORR", "COVAR_POP", "COVAR_SAMP", */ "CUBE", /* "CUME_DIST", */
+ // @TODO: Missing keywords: CURRENT_CATALOG, CURRENT_DEFAULT_TRANSFORM_GROUP
+ /* "CURRENT_CATALOG", "CURRENT_DEFAULT_TRANSFORM_GROUP", */ "CURRENT_PATH", "CURRENT_ROLE",
+ // @TODO: Missing keywords: CURRENT_SCHEMA, CURRENT_TRANSFORM_GROUP_FOR_TYPE
+ /* "CURRENT_SCHEMA", "CURRENT_TRANSFORM_GROUP_FOR_TYPE", */ "CYCLE", "DATA", "DEC",
+ // @TODO: Missing keyword: ELEMENT
+ "DEPTH", "DEREF", "DESTROY", "DESTRUCTOR", "DETERMINISTIC", "DICTIONARY", "DYNAMIC", "EACH", /* "ELEMENT", */
+ // @TODO: Missing keywords: FILTER, FULLTEXTTABLE, FUSION, HOLD
+ "EQUALS", "EVERY", /* "FILTER", */ "FREE", /* "FULLTEXTTABLE", "FUSION", */ "GENERAL", "GROUPING", /* "HOLD", */
+ // @TODO: Missing keyword: INTERSECTION
+ "HOST", "IGNORE", "INITIALIZE", "INOUT", /* "INTERSECTION", */ "ITERATE", "LARGE", "LATERAL", "LESS",
+ // @TODO: Missing keywords: LIKE_REGEX, LN, MEMBER, METHOD
+ /* "LIKE_REGEX",*/ "LIMIT", /* "LN", */ "LOCALTIME", "LOCALTIMESTAMP", "LOCATOR", "MAP", /* "MEMBER", "METHOD", */
+ // @TODO: Missing keywords: MOD, MULTISET, NORMALIZE, OCCURRENCES_REGEX
+ /* "MOD", */ "MODIFIES", "MODIFY", /* "MULTISET", */ "NCLOB", "NEW", /* "NORMALIZE", */ "OBJECT", /* "OCCURRENCES_REGEX", */
+ // @TODO: Missing keyword: OVERLAY, PARTITION
+ "OLD", "OPERATION", "ORDINALITY", "OUT", /* "OVERLAY", */ "PARAMETER", "PARAMETERS", "PARTIAL", /* "PARTITION" */
+ // @TODO: Missing keywords: PERCENT_RANK, PERCENTILE_CONT, PERCENTILE_DISC, POSITION_REGEX, RANGE
+ "PATH", "POSTFIX", "PREFIX", "PREORDER", /* "PERCENT_RANK", "PERCENTILE_CONT", "PERCENTILE_DISC", "POSITION_REGEX", "RANGE", */
+ "READS", "RECURSIVE", "REF", "REFERENCING",
+ // @TODO: Missing keywords: REGR_AVGX, REGR_AVGY, REGR_COUNT, REGR_INTERCEPT, REGR_R2, REGR_SLOPE
+ /* "REGR_AVGX", "REGR_AVGY", "REGR_COUNT", "REGR_INTERCEPT", "REGR_R2", "REGR_SLOPE", */
+ // @TODO: Missing keywords: REGR_SXX, REGR_SXY, REGR_SYY, RELEASE
+ /* "REGR_SXX", "REGR_SXY", "REGR_SYY", "RELEASE", */ "RESULT", "RETURNS", "ROLE", "ROLLUP", "ROUTINE",
+ // @TODO: Missing keywords: SENSITIVE, SIMILAR
+ "ROW", "SAVEPOINT", "SCOPE", "SEARCH", /* "SENSITIVE", */ "SEQUENCE", "SETS", /* "SIMILAR", */ "SPECIFIC",
+ // @TODO: Missing keywords: STDDEV_POP, STDDEV_SAMP
+ "SPECIFICTYPE", "SQLEXCEPTION", "START", "STATE", "STATEMENT", "STATIC", /* "STDDEV_POP", "STDDEV_SAMP", */ "STRUCTURE",
+
+ // @TODO: Missing keywords: SUBMULTISET, SUBSTRING_REGEX, SYMMETRIC, SYSTEM, TRANSLATE_REGEX, UESCAPE
+ /* "SUBMULTISET", "SUBSTRING_REGEX", "SYMMETRIC", "SYSTEM", */ "TERMINATE", "THAN", /* "TRANSLATE_REGEX", */ "TREAT", /* "UESCAPE", */
+ // @TODO: Missing keywords: VAR_POP, VAR_SAMP, WIDTH_BUCKET, WINDOW, WITHIN
+ "UNDER", "UNNEST", /* "VAR_POP", "VAR_SAMP", */ "VARIABLE", /* "WIDTH_BUCKET", */ "WITHOUT" /* , "WINDOW", "WITHIN", */
+ // @TODO: Missing keywords: XMLAGG, XMLATTRIBUTES, XMLBINARY, XMLCAST, XMLCOMMENT, XMLCONCAT, XMLDOCUMENT, XMLELEMENT, XMLEXISTS
+ /* "XMLAGG", "XMLATTRIBUTES", "XMLBINARY", "XMLCAST", "XMLCOMMENT", "XMLCONCAT", "XMLDOCUMENT", "XMLELEMENT", "XMLEXISTS", */
+ // @TODO: Missing keywords: XMLFOREST, XMLITERATE, XMLNAMESPACES, XMLPARSE, XMLPI, XMLQUERY, XMLSERIALIZE, XMLTABLE, XMLTEXT
+ /* "XMLFOREST", "XMLITERATE", "XMLNAMESPACES", "XMLPARSE", "XMLPI", "XMLQUERY", "XMLSERIALIZE", "XMLTABLE", "XMLTEXT", */
+ // @TODO: Missing keyword: XMLVALIDATE
+ /* "XMLVALIDATE" */);
+
+ // Keywords which appear in the SQL Server 2000 documentation but not in newer versions.
+ // Preserved for backwards compatibility purposes.
+ AddReservedWords(minVersion: null, maxVersion: null, "DUMMY");
+
+ reservedWordsDataTable.EndLoadData();
+ reservedWordsDataTable.AcceptChanges();
+
+ metaDataCollectionsDataSet.Tables.Add(reservedWordsDataTable);
+
+ void AddReservedWords(string? minVersion, string? maxVersion, params ReadOnlySpan reservedWords)
+ {
+ foreach (string reservedWord in reservedWords)
+ {
+ DataRow wordRow = reservedWordsDataTable.NewRow();
+
+ wordRow[DbMetaDataColumnNames.ReservedWord] = reservedWord;
+
+ if (minVersion is not null)
+ {
+ wordRow[MinimumVersionKey] = minVersion;
+ }
+
+ if (maxVersion is not null)
+ {
+ wordRow[MaximumVersionKey] = maxVersion;
+ }
+
+ reservedWordsDataTable.Rows.Add(wordRow);
+ }
+ }
+ }
+
+ private static DataTable CreateReservedWordsDataTable()
+ => new(DbMetaDataCollectionNames.ReservedWords)
+ {
+ Columns =
+ {
+ new DataColumn(DbMetaDataColumnNames.ReservedWord, typeof(string)),
+ new DataColumn(MinimumVersionKey, typeof(string)),
+ new DataColumn(MaximumVersionKey, typeof(string))
+ }
+ };
+}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlMetaDataFactory.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlMetaDataFactory.cs
index 1d9ceebafd..b5c4627f22 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlMetaDataFactory.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlMetaDataFactory.cs
@@ -715,6 +715,7 @@ private DataSet LoadDataSetFromXml(Stream XmlStream)
};
LoadDataTypesDataTables(metaDataCollectionsDataSet);
+ LoadReservedWordsDataTables(metaDataCollectionsDataSet);
XmlReaderSettings settings = new()
{
@@ -765,9 +766,6 @@ private DataSet LoadDataSetFromXml(Stream XmlStream)
dataTable = CreateDataSourceInformationDataTable();
rowFixup = FixUpDataSourceInformationRow;
break;
- case "ReservedWordsTable":
- dataTable = CreateReservedWordsDataTable();
- break;
default:
Debug.Fail($"Unexpected table element name: {reader.Name}");
break;
@@ -897,17 +895,6 @@ private static DataTable CreateDataSourceInformationDataTable()
new DataColumn(DbMetaDataColumnNames.SupportedJoinOperators, typeof(SupportedJoinOperators))
}
};
-
- private static DataTable CreateReservedWordsDataTable()
- => new(DbMetaDataCollectionNames.ReservedWords)
- {
- Columns =
- {
- new DataColumn(DbMetaDataColumnNames.ReservedWord, typeof(string)),
- new DataColumn(MinimumVersionKey, typeof(string)),
- new DataColumn(MaximumVersionKey, typeof(string))
- }
- };
#endregion
}
}
diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Microsoft.Data.SqlClient.SqlMetaData.xml b/src/Microsoft.Data.SqlClient/src/Resources/Microsoft.Data.SqlClient.SqlMetaData.xml
index 494e9a9106..dc9fae7d43 100644
--- a/src/Microsoft.Data.SqlClient/src/Resources/Microsoft.Data.SqlClient.SqlMetaData.xml
+++ b/src/Microsoft.Data.SqlClient/src/Resources/Microsoft.Data.SqlClient.SqlMetaData.xml
@@ -580,1185 +580,4 @@
15
-
-
- ADD
-
-
- EXCEPT
-
-
- PERCENT
-
-
- ALL
-
-
- EXEC
-
-
- PLAN
-
-
- ALTER
-
-
- EXECUTE
-
-
- PRECISION
-
-
- AND
-
-
- EXISTS
-
-
- PRIMARY
-
-
- ANY
-
-
- EXIT
-
-
- PRINT
-
-
- AS
-
-
- FETCH
-
-
- PROC
-
-
- ASC
-
-
- FILE
-
-
- PROCEDURE
-
-
- AUTHORIZATION
-
-
- FILLFACTOR
-
-
- PUBLIC
-
-
- BACKUP
-
-
- FOR
-
-
- RAISERROR
-
-
- BEGIN
-
-
- FOREIGN
-
-
- READ
-
-
- BETWEEN
-
-
- FREETEXT
-
-
- READTEXT
-
-
- BREAK
-
-
- FREETEXTTABLE
-
-
- RECONFIGURE
-
-
- BROWSE
-
-
- FROM
-
-
- REFERENCES
-
-
- BULK
-
-
- FULL
-
-
- REPLICATION
-
-
- BY
-
-
- FUNCTION
-
-
- RESTORE
-
-
- CASCADE
-
-
- GOTO
-
-
- RESTRICT
-
-
- CASE
-
-
- GRANT
-
-
- RETURN
-
-
- CHECK
-
-
- GROUP
-
-
- REVOKE
-
-
- CHECKPOINT
-
-
- HAVING
-
-
- RIGHT
-
-
- CLOSE
-
-
- HOLDLOCK
-
-
- ROLLBACK
-
-
- CLUSTERED
-
-
- IDENTITY
-
-
- ROWCOUNT
-
-
- COALESCE
-
-
- IDENTITY_INSERT
-
-
- ROWGUIDCOL
-
-
- COLLATE
-
-
- IDENTITYCOL
-
-
- RULE
-
-
- COLUMN
-
-
- IF
-
-
- SAVE
-
-
- COMMIT
-
-
- IN
-
-
- SCHEMA
-
-
- COMPUTE
-
-
- INDEX
-
-
- SELECT
-
-
- CONSTRAINT
-
-
- INNER
-
-
- SESSION_USER
-
-
- CONTAINS
-
-
- INSERT
-
-
- SET
-
-
- CONTAINSTABLE
-
-
- INTERSECT
-
-
- SETUSER
-
-
- CONTINUE
-
-
- INTO
-
-
- SHUTDOWN
-
-
- CONVERT
-
-
- IS
-
-
- SOME
-
-
- CREATE
-
-
- JOIN
-
-
- STATISTICS
-
-
- CROSS
-
-
- KEY
-
-
- SYSTEM_USER
-
-
- CURRENT
-
-
- KILL
-
-
- TABLE
-
-
- CURRENT_DATE
-
-
- LEFT
-
-
- TEXTSIZE
-
-
- CURRENT_TIME
-
-
- LIKE
-
-
- THEN
-
-
- CURRENT_TIMESTAMP
-
-
- LINENO
-
-
- TO
-
-
- CURRENT_USER
-
-
- LOAD
-
-
- TOP
-
-
- CURSOR
-
-
- NATIONAL
-
-
- TRAN
-
-
- DATABASE
-
-
- NOCHECK
-
-
- TRANSACTION
-
-
- DBCC
-
-
- NONCLUSTERED
-
-
- TRIGGER
-
-
- DEALLOCATE
-
-
- NOT
-
-
- TRUNCATE
-
-
- DECLARE
-
-
- NULL
-
-
- TSEQUAL
-
-
- DEFAULT
-
-
- NULLIF
-
-
- UNION
-
-
- DELETE
-
-
- OF
-
-
- UNIQUE
-
-
- DENY
-
-
- OFF
-
-
- UPDATE
-
-
- DESC
-
-
- OFFSETS
-
-
- UPDATETEXT
-
-
- DISK
-
-
- ON
-
-
- USE
-
-
- DISTINCT
-
-
- OPEN
-
-
- USER
-
-
- DISTRIBUTED
-
-
- OPENDATASOURCE
-
-
- VALUES
-
-
- DOUBLE
-
-
- OPENQUERY
-
-
- VARYING
-
-
- DROP
-
-
- OPENROWSET
-
-
- VIEW
-
-
- DUMMY
-
-
- OPENXML
-
-
- WAITFOR
-
-
- DUMP
-
-
- OPTION
-
-
- WHEN
-
-
- ELSE
-
-
- OR
-
-
- WHERE
-
-
- END
-
-
- ORDER
-
-
- WHILE
-
-
- ERRLVL
-
-
- OUTER
-
-
- WITH
-
-
- ESCAPE
-
-
- OVER
-
-
- WRITETEXT
-
-
- ABSOLUTE
-
-
- FOUND
-
-
- PRESERVE
-
-
- ACTION
-
-
- FREE
-
-
- PRIOR
-
-
- ADMIN
-
-
- GENERAL
-
-
- PRIVILEGES
-
-
- AFTER
-
-
- GET
-
-
- READS
-
-
- AGGREGATE
-
-
- GLOBAL
-
-
- REAL
-
-
- ALIAS
-
-
- GO
-
-
- RECURSIVE
-
-
- ALLOCATE
-
-
- GROUPING
-
-
- REF
-
-
- ARE
-
-
- HOST
-
-
- REFERENCING
-
-
- ARRAY
-
-
- HOUR
-
-
- RELATIVE
-
-
- ASSERTION
-
-
- IGNORE
-
-
- RESULT
-
-
- AT
-
-
- IMMEDIATE
-
-
- RETURNS
-
-
- BEFORE
-
-
- INDICATOR
-
-
- ROLE
-
-
- BINARY
-
-
- INITIALIZE
-
-
- ROLLUP
-
-
- BIT
-
-
- INITIALLY
-
-
- ROUTINE
-
-
- BLOB
-
-
- INOUT
-
-
- ROW
-
-
- BOOLEAN
-
-
- INPUT
-
-
- ROWS
-
-
- BOTH
-
-
- INT
-
-
- SAVEPOINT
-
-
- BREADTH
-
-
- INTEGER
-
-
- SCROLL
-
-
- CALL
-
-
- INTERVAL
-
-
- SCOPE
-
-
- CASCADED
-
-
- ISOLATION
-
-
- SEARCH
-
-
- CAST
-
-
- ITERATE
-
-
- SECOND
-
-
- CATALOG
-
-
- LANGUAGE
-
-
- SECTION
-
-
- CHAR
-
-
- LARGE
-
-
- SEQUENCE
-
-
- CHARACTER
-
-
- LAST
-
-
- SESSION
-
-
- CLASS
-
-
- LATERAL
-
-
- SETS
-
-
- CLOB
-
-
- LEADING
-
-
- SIZE
-
-
- COLLATION
-
-
- LESS
-
-
- SMALLINT
-
-
- COMPLETION
-
-
- LEVEL
-
-
- SPACE
-
-
- CONNECT
-
-
- LIMIT
-
-
- SPECIFIC
-
-
- CONNECTION
-
-
- LOCAL
-
-
- SPECIFICTYPE
-
-
- CONSTRAINTS
-
-
- LOCALTIME
-
-
- SQL
-
-
- CONSTRUCTOR
-
-
- LOCALTIMESTAMP
-
-
- SQLEXCEPTION
-
-
- CORRESPONDING
-
-
- LOCATOR
-
-
- SQLSTATE
-
-
- CUBE
-
-
- MAP
-
-
- SQLWARNING
-
-
- CURRENT_PATH
-
-
- MATCH
-
-
- START
-
-
- CURRENT_ROLE
-
-
- MINUTE
-
-
- STATE
-
-
- CYCLE
-
-
- MODIFIES
-
-
- STATEMENT
-
-
- DATA
-
-
- MODIFY
-
-
- STATIC
-
-
- DATE
-
-
- MODULE
-
-
- STRUCTURE
-
-
- DAY
-
-
- MONTH
-
-
- TEMPORARY
-
-
- DEC
-
-
- NAMES
-
-
- TERMINATE
-
-
- DECIMAL
-
-
- NATURAL
-
-
- THAN
-
-
- DEFERRABLE
-
-
- NCHAR
-
-
- TIME
-
-
- DEFERRED
-
-
- NCLOB
-
-
- TIMESTAMP
-
-
- DEPTH
-
-
- NEW
-
-
- TIMEZONE_HOUR
-
-
- DEREF
-
-
- NEXT
-
-
- TIMEZONE_MINUTE
-
-
- DESCRIBE
-
-
- NO
-
-
- TRAILING
-
-
- DESCRIPTOR
-
-
- NONE
-
-
- TRANSLATION
-
-
- DESTROY
-
-
- NUMERIC
-
-
- TREAT
-
-
- DESTRUCTOR
-
-
- OBJECT
-
-
- TRUE
-
-
- DETERMINISTIC
-
-
- OLD
-
-
- UNDER
-
-
- DICTIONARY
-
-
- ONLY
-
-
- UNKNOWN
-
-
- DIAGNOSTICS
-
-
- OPERATION
-
-
- UNNEST
-
-
- DISCONNECT
-
-
- ORDINALITY
-
-
- USAGE
-
-
- DOMAIN
-
-
- OUT
-
-
- USING
-
-
- DYNAMIC
-
-
- OUTPUT
-
-
- VALUE
-
-
- EACH
-
-
- PAD
-
-
- VARCHAR
-
-
- END-EXEC
-
-
- PARAMETER
-
-
- VARIABLE
-
-
- EQUALS
-
-
- PARAMETERS
-
-
- WHENEVER
-
-
- EVERY
-
-
- PARTIAL
-
-
- WITHOUT
-
-
- EXCEPTION
-
-
- PATH
-
-
- WORK
-
-
- EXTERNAL
-
-
- POSTFIX
-
-
- WRITE
-
-
- FALSE
-
-
- PREFIX
-
-
- YEAR
-
-
- FIRST
-
-
- PREORDER
-
-
- ZONE
-
-
- FLOAT
-
-
- PREPARE
-
-
- ADA
-
-
- AVG
-
-
- BIT_LENGTH
-
-
- CHAR_LENGTH
-
-
- CHARACTER_LENGTH
-
-
- COUNT
-
-
- EXTRACT
-
-
- FORTRAN
-
-
- INCLUDE
-
-
- INSENSITIVE
-
-
- LOWER
-
-
- MAX
-
-
- MIN
-
-
- OCTET_LENGTH
-
-
- OVERLAPS
-
-
- PASCAL
-
-
- POSITION
-
-
- SQLCA
-
-
- SQLCODE
-
-
- SQLERROR
-
-
- SUBSTRING
-
-
- SUM
-
-
- TRANSLATE
-
-
- TRIM
-
-
- UPPER
-
-
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataBaseSchemaTest/ConnectionSchemaTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataBaseSchemaTest/ConnectionSchemaTest.cs
index 028447251c..44f51ac161 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataBaseSchemaTest/ConnectionSchemaTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataBaseSchemaTest/ConnectionSchemaTest.cs
@@ -55,6 +55,15 @@ public static async Task GetIndexesFromSchema()
await VerifySchemaTable(SqlClientMetaDataCollectionNames.Indexes, new string[] { "index_name", "constraint_name" });
}
+ [ConditionalFact(nameof(CanRunSchemaTests))]
+ public static async Task GetReservedWordsFromSchema()
+ {
+ (DataTable syncReservedWordTable, DataTable asyncReservedWordsTable) = await VerifySchemaTable(DbMetaDataCollectionNames.ReservedWords, new string[] { "ReservedWord" });
+
+ VerifyReservedWordsTable(syncReservedWordTable);
+ VerifyReservedWordsTable(asyncReservedWordsTable);
+ }
+
[ConditionalFact(nameof(CanRunSchemaTests))]
public static async Task GetIndexColumnsFromSchema()
{
@@ -198,5 +207,36 @@ private static void VerifyDataTypesTable(DataTable dataTypesTable)
// SQL Azure reports a version of 12.x but supports JSON, so SqlClient doesn't include it in the list of types.
Assert.Equal(DataTestUtility.IsJsonSupported && DataTestUtility.IsNotAzureServer(), actualTypes.Contains("json"));
}
+
+ private static void VerifyReservedWordsTable(DataTable reservedWordsTable)
+ {
+ // This set contains four example words from each of the categories of reserved words
+ string[] sampleReservedWords = [
+ // SQL Server reserved words
+ "SELECT", "FROM", "WHERE", "NATIONAL",
+ // ODBC reserved words
+ "GO", "COUNT", "SQLCODE", "SMALLINT",
+ // Future reserved keywords
+ "AGGREGATE", "ALIAS", "DATA", "LOCALTIME",
+ // Older keyword
+ "DUMMY"
+ ];
+ HashSet actualReservedWords = [];
+
+ // Assert that every reserved word is unique.
+ foreach (DataRow row in reservedWordsTable.Rows)
+ {
+ string reservedWord = row[DbMetaDataColumnNames.ReservedWord] as string;
+
+ Assert.False(string.IsNullOrEmpty(reservedWord));
+ // Older versions of SqlClient included a keyword of "NATIONAL " (note the trailing space.)
+ // Verify that this is no longer possible.
+ Assert.Equal(reservedWord.Trim(), reservedWord);
+ Assert.True(actualReservedWords.Add(reservedWord));
+ }
+
+ Assert.All(sampleReservedWords, reservedWord => Assert.Contains(reservedWord, actualReservedWords));
+ Assert.Equal(393, actualReservedWords.Count);
+ }
}
}