Skip to content

Commit e3df5b3

Browse files
committed
SchemaObject abstract base — unify the metadata of every named schema-resident database object behind one type. HeapTable / View / Procedure / Sequence / TableType / Trigger / UserDefinedFunction (and its ScalarFunction / InlineTableValuedFunction sealed derivees) all : SchemaObject(name, objectId, schemaId, createDate) now; their duplicated Name / ObjectId / CreateDate fields are gone. The base also stores ModifyDate (mutable, defaults to CreateDate so the ALTER-bumps-modify-date hook lands in one place) and exposes two abstract members — ObjectTypeCode (the 2-char sys.objects.type: 'U '/'V '/'P '/'FN'/'IF'/'TR'/'SO'/'TT') and ObjectTypeDescription ('USER_TABLE'/'VIEW'/etc.) — so catalog-view projection reads the discriminator directly off the instance rather than threading 18 precomputed SqlValues through helper methods. TableType.TypeTableObjectId folded into the inherited ObjectId (and that's now what sys.table_types.type_table_object_id projects). Trigger.Parent typed as SchemaObject (was object); the ParentObjectId runtime-switch property gone — call sites read trigger.Parent.ObjectId directly. DML hook parameters (Update / Delete / Drop / InvokeTrigger) retyped object→SchemaObject; the (object?)sourceView ?? table ternaries become (SchemaObject?)sourceView ?? table. New Schema.SchemaObjects() yields every object in the shared object-name namespace (HeapTables + Views + Functions + Procedures + Sequences + Triggers — TableTypes deliberately excluded since probe-confirmed those occupy a separate namespace), and Schema.HasNameInSharedNamespace(leaf) tightens the previously-inconsistent CREATE-time Msg 2714 check: CREATE TABLE was missing the cross-kind scan entirely; CREATE FUNCTION checked only 2 dicts; CREATE VIEW checked 3; CREATE PROCEDURE checked 3; CREATE SEQUENCE checked 4; CREATE TRIGGER checked 5. All six paths now call the same one-line predicate and reject every shared-namespace collision (matches real SQL Server's behavior — none of the existing tests broke since each one was already testing within its dict's scope). sys.objects iteration collapses from 5 manually-ordered kind groups with hand-coded type/typeDesc per yield to a single schema.SchemaObjects().OrderBy(o => o.ObjectId) loop reading obj.ObjectTypeCode / obj.ObjectTypeDescription directly; constraint rows (PK / UQ / CHECK) still emit immediately after their owning HeapTable so the natural ordering matches probe. EnumerateProcedures / EnumerateSysTriggers stay single-kind enumerators with hoisted type/typeDesc constants for per-row allocation savings. 3326 / 264 tests pass; dotnet format clean. No behavior change beyond the tightened CREATE-time collision check.
1 parent 71ed92f commit e3df5b3

21 files changed

Lines changed: 241 additions & 262 deletions

SqlServerSimulator/BuiltInResources.cs

Lines changed: 61 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -167,27 +167,21 @@ private static Dictionary<string, CatalogView> BuildCatalogViews()
167167
notMsShipped,
168168
}));
169169

170-
// sys.objects: a superset of sys.tables that also emits one row per
171-
// PK / UQ / CHECK constraint, with parent_object_id linking back to
172-
// the owning table. type_desc strings probe-confirmed: 'U ' /
173-
// USER_TABLE, 'PK' / PRIMARY_KEY_CONSTRAINT, 'UQ' / UNIQUE_CONSTRAINT,
174-
// 'C ' / CHECK_CONSTRAINT.
170+
// sys.objects: every <see cref="SchemaObject"/> emits one row, plus
171+
// one extra row per HeapTable PK / UQ / CHECK constraint linked via
172+
// parent_object_id. type / type_desc come from the SchemaObject's
173+
// own ObjectTypeCode / ObjectTypeDescription (probe-confirmed
174+
// values: 'U ' / USER_TABLE, 'V ' / VIEW, 'P ' / SQL_STORED_PROCEDURE,
175+
// 'FN' / SQL_SCALAR_FUNCTION, 'IF' / SQL_INLINE_TABLE_VALUED_FUNCTION,
176+
// 'TR' / SQL_TRIGGER). Constraint codes ('PK', 'UQ', 'C ') live
177+
// outside the SchemaObject contract since constraints aren't first-
178+
// class schema objects.
175179
var pkType = SqlValue.FromChar(charTwo, "PK");
176180
var pkTypeDesc = SqlValue.FromNVarchar("PRIMARY_KEY_CONSTRAINT");
177181
var uqType = SqlValue.FromChar(charTwo, "UQ");
178182
var uqTypeDesc = SqlValue.FromNVarchar("UNIQUE_CONSTRAINT");
179183
var checkType = SqlValue.FromChar(charTwo, "C ");
180184
var checkTypeDesc = SqlValue.FromNVarchar("CHECK_CONSTRAINT");
181-
var fnType = SqlValue.FromChar(charTwo, "FN");
182-
var fnTypeDesc = SqlValue.FromNVarchar("SQL_SCALAR_FUNCTION");
183-
var inlineTvfType = SqlValue.FromChar(charTwo, "IF");
184-
var inlineTvfTypeDesc = SqlValue.FromNVarchar("SQL_INLINE_TABLE_VALUED_FUNCTION");
185-
var viewType = SqlValue.FromChar(charTwo, "V ");
186-
var viewTypeDesc = SqlValue.FromNVarchar("VIEW");
187-
var procType = SqlValue.FromChar(charTwo, "P ");
188-
var procTypeDesc = SqlValue.FromNVarchar("SQL_STORED_PROCEDURE");
189-
var triggerType = SqlValue.FromChar(charTwo, "TR");
190-
var triggerTypeDesc = SqlValue.FromNVarchar("SQL_TRIGGER");
191185
var zeroParent = SqlValue.FromInt32(0);
192186
var objectsColumns = new HeapColumn[]
193187
{
@@ -202,7 +196,7 @@ private static Dictionary<string, CatalogView> BuildCatalogViews()
202196
new("is_ms_shipped", SqlType.Bit, null, true),
203197
};
204198
var objectsView = new CatalogView("objects", objectsColumns, batch =>
205-
EnumerateObjects(batch, tableType, tableTypeDesc, pkType, pkTypeDesc, uqType, uqTypeDesc, checkType, checkTypeDesc, fnType, fnTypeDesc, inlineTvfType, inlineTvfTypeDesc, viewType, viewTypeDesc, procType, procTypeDesc, triggerType, triggerTypeDesc, zeroParent, notMsShipped));
199+
EnumerateObjects(batch, charTwo, pkType, pkTypeDesc, uqType, uqTypeDesc, checkType, checkTypeDesc, zeroParent, notMsShipped));
206200

207201
// sys.columns: load-bearing subset of real SQL Server's column set.
208202
// Probe-confirmed (2026-05-11): max_length is byte-length (4 for int,
@@ -367,7 +361,7 @@ private static Dictionary<string, CatalogView> BuildCatalogViews()
367361
new("is_ms_shipped", SqlType.Bit, null, false),
368362
};
369363
var proceduresView = new CatalogView("procedures", proceduresColumns, batch =>
370-
EnumerateProcedures(batch, procType, procTypeDesc, notMsShipped));
364+
EnumerateProcedures(batch, charTwo, notMsShipped));
371365

372366
// INFORMATION_SCHEMA.ROUTINES: ISO-shape view listing both procedures
373367
// and functions. The simulator ships the load-bearing column subset:
@@ -522,7 +516,7 @@ private static Dictionary<string, CatalogView> BuildCatalogViews()
522516
new("is_not_for_replication", SqlType.Bit, null, false),
523517
};
524518
var triggersView = new CatalogView("triggers", triggersColumns, batch =>
525-
EnumerateSysTriggers(batch, parentClassObjectColumn, parentClassObjectColumnDesc, triggerType, triggerTypeDesc));
519+
EnumerateSysTriggers(batch, charTwo, parentClassObjectColumn, parentClassObjectColumnDesc));
526520

527521
// INFORMATION_SCHEMA.DOMAINS: ISO-standard surface. Real SQL Server
528522
// emits a row for every user-defined type (scalar UDTs surface their
@@ -624,7 +618,7 @@ private static IEnumerable<SqlValue[]> EnumerateSysTableTypes(Parser.BatchContex
624618
{
625619
yield return [
626620
SqlValue.FromSystemName(tt.Name),
627-
SqlValue.FromInt32(tt.TypeTableObjectId),
621+
SqlValue.FromInt32(tt.ObjectId),
628622
trueBit,
629623
schemaId,
630624
SqlValue.FromInt32(tt.UserTypeId),
@@ -651,13 +645,17 @@ private static IEnumerable<SqlValue[]> EnumerateSysTableTypes(Parser.BatchContex
651645
/// </summary>
652646
private static IEnumerable<SqlValue[]> EnumerateSysTriggers(
653647
Parser.BatchContext batch,
648+
SqlType charTwo,
654649
SqlValue parentClassObjectColumn,
655-
SqlValue parentClassObjectColumnDesc,
656-
SqlValue triggerType,
657-
SqlValue triggerTypeDesc)
650+
SqlValue parentClassObjectColumnDesc)
658651
{
659652
var trueBit = SqlValue.FromBoolean(true);
660653
var falseBit = SqlValue.FromBoolean(false);
654+
// 'TR' / 'SQL_TRIGGER' — matches Trigger.ObjectTypeCode /
655+
// Trigger.ObjectTypeDescription, kept as local constants here to
656+
// avoid one SqlValue allocation per row.
657+
var triggerType = SqlValue.FromChar(charTwo, "TR");
658+
var triggerTypeDesc = SqlValue.FromNVarchar("SQL_TRIGGER");
661659
foreach (var schema in batch.CurrentDatabase.Schemas.Values)
662660
{
663661
foreach (var trigger in schema.Triggers.Values.OrderBy(t => t.ObjectId))
@@ -668,7 +666,7 @@ private static IEnumerable<SqlValue[]> EnumerateSysTriggers(
668666
SqlValue.FromInt32(trigger.ObjectId),
669667
parentClassObjectColumn,
670668
parentClassObjectColumnDesc,
671-
SqlValue.FromInt32(trigger.ParentObjectId),
669+
SqlValue.FromInt32(trigger.Parent.ObjectId),
672670
triggerType,
673671
triggerTypeDesc,
674672
createDate,
@@ -751,17 +749,21 @@ private static IEnumerable<SqlValue[]> EnumerateInformationSchemaDomains(Parser.
751749
/// Rows for <c>sys.procedures</c>: one row per <see cref="Procedure"/> in
752750
/// every schema. The full <c>create_date</c> / <c>modify_date</c> story
753751
/// in real SQL Server tracks ALTER PROCEDURE separately; the simulator
754-
/// uses the ALTER-preserving <see cref="Procedure.CreateDate"/> for both
752+
/// uses the ALTER-preserving <see cref="SchemaObject.CreateDate"/> for both
755753
/// columns (the original create date survives ALTER, matching the way
756-
/// <see cref="Procedure.ObjectId"/> survives — minor fidelity gap on
754+
/// <see cref="SchemaObject.ObjectId"/> survives — minor fidelity gap on
757755
/// modify_date which would shift on each ALTER in real SQL Server).
758756
/// </summary>
759757
private static IEnumerable<SqlValue[]> EnumerateProcedures(
760758
Parser.BatchContext batch,
761-
SqlValue procType,
762-
SqlValue procTypeDesc,
759+
SqlType charTwo,
763760
SqlValue notMsShipped)
764761
{
762+
// 'P ' / 'SQL_STORED_PROCEDURE' — matches Procedure.ObjectTypeCode /
763+
// Procedure.ObjectTypeDescription, kept as local constants here to
764+
// avoid one SqlValue allocation per row.
765+
var procType = SqlValue.FromChar(charTwo, "P ");
766+
var procTypeDesc = SqlValue.FromNVarchar("SQL_STORED_PROCEDURE");
765767
foreach (var schema in batch.CurrentDatabase.Schemas.Values)
766768
{
767769
foreach (var proc in schema.Procedures.Values.OrderBy(p => p.ObjectId))
@@ -1110,9 +1112,9 @@ private static IEnumerable<SqlValue[]> EnumerateColumns(
11101112
// Table types surface their columns through sys.columns keyed by
11111113
// type_table_object_id (probe G3). Computed columns inherit
11121114
// is_computed=true; identity columns inherit is_identity=true.
1113-
foreach (var tt in schema.TableTypes.Values.OrderBy(t => t.TypeTableObjectId))
1115+
foreach (var tt in schema.TableTypes.Values.OrderBy(t => t.ObjectId))
11141116
{
1115-
var typeObjectId = SqlValue.FromInt32(tt.TypeTableObjectId);
1117+
var typeObjectId = SqlValue.FromInt32(tt.ObjectId);
11161118
for (var i = 0; i < tt.Columns.Length; i++)
11171119
{
11181120
var col = tt.Columns[i];
@@ -1346,104 +1348,52 @@ private static (int? CharLength, int? OctetLength, byte? NumericPrecision, int?
13461348

13471349
private static IEnumerable<SqlValue[]> EnumerateObjects(
13481350
Parser.BatchContext batch,
1349-
SqlValue tableType, SqlValue tableTypeDesc,
1351+
SqlType charTwo,
13501352
SqlValue pkType, SqlValue pkTypeDesc,
13511353
SqlValue uqType, SqlValue uqTypeDesc,
13521354
SqlValue checkType, SqlValue checkTypeDesc,
1353-
SqlValue fnType, SqlValue fnTypeDesc,
1354-
SqlValue inlineTvfType, SqlValue inlineTvfTypeDesc,
1355-
SqlValue viewType, SqlValue viewTypeDesc,
1356-
SqlValue procType, SqlValue procTypeDesc,
1357-
SqlValue triggerType, SqlValue triggerTypeDesc,
13581355
SqlValue zeroParent, SqlValue notMsShipped)
13591356
{
13601357
foreach (var schema in batch.CurrentDatabase.Schemas.Values)
13611358
{
1362-
foreach (var fn in schema.Functions.Values.OrderBy(f => f.ObjectId))
1363-
{
1364-
var (typeCode, typeDesc) = fn switch
1365-
{
1366-
InlineTableValuedFunction => (inlineTvfType, inlineTvfTypeDesc),
1367-
_ => (fnType, fnTypeDesc),
1368-
};
1369-
yield return [
1370-
SqlValue.FromInt32(fn.ObjectId),
1371-
SqlValue.FromSystemName(fn.Name),
1372-
SqlValue.FromInt32(fn.Schema.SchemaId),
1373-
zeroParent,
1374-
typeCode,
1375-
typeDesc,
1376-
SqlValue.FromDateTime(fn.CreateDate),
1377-
SqlValue.FromDateTime(fn.CreateDate),
1378-
notMsShipped,
1379-
];
1380-
}
1381-
foreach (var view in schema.Views.Values.OrderBy(v => v.ObjectId))
1382-
{
1383-
yield return [
1384-
SqlValue.FromInt32(view.ObjectId),
1385-
SqlValue.FromSystemName(view.Name),
1386-
SqlValue.FromInt32(view.Schema.SchemaId),
1387-
zeroParent,
1388-
viewType,
1389-
viewTypeDesc,
1390-
SqlValue.FromDateTime(view.CreateDate),
1391-
SqlValue.FromDateTime(view.CreateDate),
1392-
notMsShipped,
1393-
];
1394-
}
1395-
foreach (var proc in schema.Procedures.Values.OrderBy(p => p.ObjectId))
1396-
{
1397-
yield return [
1398-
SqlValue.FromInt32(proc.ObjectId),
1399-
SqlValue.FromSystemName(proc.Name),
1400-
SqlValue.FromInt32(proc.Schema.SchemaId),
1401-
zeroParent,
1402-
procType,
1403-
procTypeDesc,
1404-
SqlValue.FromDateTime(proc.CreateDate),
1405-
SqlValue.FromDateTime(proc.CreateDate),
1406-
notMsShipped,
1407-
];
1408-
}
1409-
foreach (var trigger in schema.Triggers.Values.OrderBy(t => t.ObjectId))
1359+
// Schema-resident objects in ObjectId order. SchemaObject's
1360+
// ObjectTypeCode / ObjectTypeDescription supply the discriminators,
1361+
// so adding a new schema-object kind (e.g. surfacing Sequences /
1362+
// TableTypes in sys.objects later) only requires implementing the
1363+
// two abstract members on that type.
1364+
foreach (var obj in schema.SchemaObjects().OrderBy(o => o.ObjectId))
14101365
{
1366+
var parent = obj is Trigger trigger
1367+
? SqlValue.FromInt32(trigger.Parent.ObjectId)
1368+
: zeroParent;
14111369
yield return [
1412-
SqlValue.FromInt32(trigger.ObjectId),
1413-
SqlValue.FromSystemName(trigger.Name),
1414-
SqlValue.FromInt32(trigger.Schema.SchemaId),
1415-
SqlValue.FromInt32(trigger.ParentObjectId),
1416-
triggerType,
1417-
triggerTypeDesc,
1418-
SqlValue.FromDateTime(trigger.CreateDate),
1419-
SqlValue.FromDateTime(trigger.CreateDate),
1370+
SqlValue.FromInt32(obj.ObjectId),
1371+
SqlValue.FromSystemName(obj.Name),
1372+
SqlValue.FromInt32(obj.SchemaId),
1373+
parent,
1374+
SqlValue.FromChar(charTwo, obj.ObjectTypeCode),
1375+
SqlValue.FromNVarchar(obj.ObjectTypeDescription),
1376+
SqlValue.FromDateTime(obj.CreateDate),
1377+
SqlValue.FromDateTime(obj.ModifyDate),
14201378
notMsShipped,
14211379
];
1422-
}
1423-
foreach (var t in schema.HeapTables.Values.OrderBy(t => t.ObjectId))
1424-
{
1425-
var schemaId = SqlValue.FromInt32(t.SchemaId);
1380+
1381+
// Constraint rows hang off HeapTable parents — emit them
1382+
// immediately after the table they belong to so the natural
1383+
// sys.objects ordering matches probe-confirmed real-server
1384+
// shape (table rows interleaved with their own constraints).
1385+
if (obj is not HeapTable t) continue;
1386+
var schemaIdValue = SqlValue.FromInt32(t.SchemaId);
14261387
var createDate = SqlValue.FromDateTime(t.CreateDate);
14271388
var modifyDate = SqlValue.FromDateTime(t.ModifyDate);
1428-
yield return [
1429-
SqlValue.FromInt32(t.ObjectId),
1430-
SqlValue.FromSystemName(t.Name),
1431-
schemaId,
1432-
zeroParent,
1433-
tableType,
1434-
tableTypeDesc,
1435-
createDate,
1436-
modifyDate,
1437-
notMsShipped,
1438-
];
1439-
var parent = SqlValue.FromInt32(t.ObjectId);
1389+
var tableObjectId = SqlValue.FromInt32(t.ObjectId);
14401390
foreach (var key in t.KeyConstraints)
14411391
{
14421392
yield return [
14431393
SqlValue.FromInt32(key.ObjectId),
14441394
SqlValue.FromSystemName(key.Name),
1445-
schemaId,
1446-
parent,
1395+
schemaIdValue,
1396+
tableObjectId,
14471397
key.Kind == KeyConstraintKind.PrimaryKey ? pkType : uqType,
14481398
key.Kind == KeyConstraintKind.PrimaryKey ? pkTypeDesc : uqTypeDesc,
14491399
createDate,
@@ -1456,8 +1406,8 @@ private static IEnumerable<SqlValue[]> EnumerateObjects(
14561406
yield return [
14571407
SqlValue.FromInt32(chk.ObjectId),
14581408
SqlValue.FromSystemName(chk.Name),
1459-
schemaId,
1460-
parent,
1409+
schemaIdValue,
1410+
tableObjectId,
14611411
checkType,
14621412
checkTypeDesc,
14631413
createDate,

SqlServerSimulator/Parser/FromSource.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ internal sealed class FromSource(
4949
/// Back-reference to the <see cref="HeapTable"/> when this source is a
5050
/// table (or system table); null for derived-table sources. Used by the
5151
/// UPDATE / DELETE mutation paths to reach the table's
52-
/// <see cref="HeapTable.KeyConstraints"/> / <see cref="HeapTable.Name"/>
52+
/// <see cref="HeapTable.KeyConstraints"/> / <see cref="SchemaObject.Name"/>
5353
/// after FROM parsing has identified which source is the mutation target.
5454
/// </summary>
5555
public readonly HeapTable? BackingTable = backingTable;

SqlServerSimulator/Procedure.cs

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,12 @@ internal sealed class Procedure(
3737
ProcedureParameter[] parameters,
3838
string bodyText,
3939
DateTime createDate)
40+
: SchemaObject(name, objectId, schema.SchemaId, createDate)
4041
{
4142
public readonly Schema Schema = schema;
42-
public readonly string Name = name;
4343

44-
/// <summary>
45-
/// Stable per-database identifier; preserved across <c>ALTER PROCEDURE</c>
46-
/// (probe-confirmed: real SQL Server's ALTER keeps the same object_id, so
47-
/// foreign refs in <c>sys.objects</c> stay consistent). Allocated at
48-
/// CREATE PROCEDURE time from <see cref="Database.AllocateObjectId"/>;
49-
/// stored mutable-by-ALTER on the procedure record. Replaced wholesale on
50-
/// each ALTER because parameter list / body text both swap; the field is
51-
/// readonly because the ALTER path constructs a fresh <see cref="Procedure"/>
52-
/// instance carrying the preserved id.
53-
/// </summary>
54-
public readonly int ObjectId = objectId;
44+
public override string ObjectTypeCode => "P ";
45+
public override string ObjectTypeDescription => "SQL_STORED_PROCEDURE";
5546

5647
/// <summary>
5748
/// Declared parameters in source order. Each carries name, type, optional
@@ -70,8 +61,6 @@ internal sealed class Procedure(
7061
/// invoked).
7162
/// </summary>
7263
public readonly string BodyText = bodyText;
73-
74-
public readonly DateTime CreateDate = createDate;
7564
}
7665

7766
/// <summary>

SqlServerSimulator/Schema.cs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ internal sealed class Schema(string name, int schemaId)
5454
/// resolves through this dict. Procedures share the object-name
5555
/// namespace with tables / views / functions (Msg 2714 on collision).
5656
/// <c>ALTER PROCEDURE</c> replaces the entry while preserving the
57-
/// existing <see cref="Procedure.ObjectId"/>; <c>DROP PROCEDURE</c>
57+
/// existing <see cref="SchemaObject.ObjectId"/>; <c>DROP PROCEDURE</c>
5858
/// removes it.
5959
/// </summary>
6060
public readonly ConcurrentDictionary<string, Procedure> Procedures = new(Collation.Default);
@@ -91,4 +91,39 @@ internal sealed class Schema(string name, int schemaId)
9191
/// of truth (ENABLE / DISABLE / DROP all operate on it).
9292
/// </summary>
9393
public readonly ConcurrentDictionary<string, Trigger> Triggers = new(Collation.Default);
94+
95+
/// <summary>
96+
/// Yields every <see cref="SchemaObject"/> in this schema's
97+
/// object-name namespace (heap tables, views, UDFs, procedures,
98+
/// sequences, triggers) — the set whose leaf names must be unique
99+
/// (Msg 2714 on CREATE collision). <see cref="TableTypes"/> are
100+
/// deliberately omitted: probe-confirmed that table-type names occupy
101+
/// a separate namespace from this set. Used by sys.objects projection
102+
/// and by the CREATE-time auto-name-collision check.
103+
/// </summary>
104+
public IEnumerable<SchemaObject> SchemaObjects()
105+
{
106+
foreach (var t in this.HeapTables.Values) yield return t;
107+
foreach (var v in this.Views.Values) yield return v;
108+
foreach (var fn in this.Functions.Values) yield return fn;
109+
foreach (var p in this.Procedures.Values) yield return p;
110+
foreach (var s in this.Sequences.Values) yield return s;
111+
foreach (var tr in this.Triggers.Values) yield return tr;
112+
}
113+
114+
/// <summary>
115+
/// True when <paramref name="leaf"/> matches any existing name in
116+
/// this schema's object-name namespace (<see cref="SchemaObjects"/>).
117+
/// Used by every CREATE path to raise Msg 2714 before allocating an
118+
/// ObjectId or writing into the relevant dict.
119+
/// </summary>
120+
public bool HasNameInSharedNamespace(string leaf)
121+
{
122+
foreach (var obj in this.SchemaObjects())
123+
{
124+
if (Collation.Default.Equals(obj.Name, leaf))
125+
return true;
126+
}
127+
return false;
128+
}
94129
}

0 commit comments

Comments
 (0)