@@ -88,7 +88,7 @@ public static bool TcpConnectionStringDoesNotUseAadAuth
88
88
{
89
89
get
90
90
{
91
- SqlConnectionStringBuilder builder = new ( TCPConnectionString ) ;
91
+ SqlConnectionStringBuilder builder = new ( TCPConnectionString ) ;
92
92
return builder . Authentication == SqlAuthenticationMethod . SqlPassword || builder . Authentication == SqlAuthenticationMethod . NotSpecified ;
93
93
}
94
94
}
@@ -415,59 +415,176 @@ public static bool DoesHostAddressContainBothIPv4AndIPv6()
415
415
}
416
416
}
417
417
418
+ // Generate a new GUID and return the characters from its 1st and 4th
419
+ // parts, as shown here:
420
+ //
421
+ // 7ff01cb8-88c7-11f0-b433-00155d7e531e
422
+ // ^^^^^^^^ ^^^^
423
+ //
424
+ // These 12 characters are concatenated together without any
425
+ // separators. These 2 parts typically comprise a timestamp and clock
426
+ // sequence, most likely to be unique for tests that generate names in
427
+ // quick succession.
428
+ private static string GetGuidParts ( )
429
+ {
430
+ var guid = Guid . NewGuid ( ) . ToString ( ) ;
431
+ // GOTCHA: The slice operator is inclusive of the start index and
432
+ // exclusive of the end index!
433
+ return guid . Substring ( 0 , 8 ) + guid . Substring ( 19 , 4 ) ;
434
+ }
435
+
418
436
/// <summary>
419
- /// Generate a unique name to use in Sql Server;
420
- /// some providers does not support names (Oracle supports up to 30).
437
+ /// Generate a short unique database object name, whose maximum length
438
+ /// is 30 characters, with the format:
439
+ ///
440
+ /// <Prefix>_<GuidParts>
441
+ ///
442
+ /// The Prefix will be truncated to satisfy the overall maximum length.
443
+ ///
444
+ /// The GUID parts will be the characters from the 1st and 4th blocks
445
+ /// from a traditional string representation, as shown here:
446
+ ///
447
+ /// 7ff01cb8-88c7-11f0-b433-00155d7e531e
448
+ /// ^^^^^^^^ ^^^^
449
+ ///
450
+ /// These 2 parts typically comprise a timestamp and clock sequence,
451
+ /// most likely to be unique for tests that generate names in quick
452
+ /// succession. The 12 characters are concatenated together without any
453
+ /// separators.
421
454
/// </summary>
422
- /// <param name="prefix">The name length will be no more then (16 + prefix.Length + escapeLeft.Length + escapeRight.Length).</param>
423
- /// <param name="withBracket">Name without brackets.</param>
424
- /// <returns>Unique name by considering the Sql Server naming rules.</returns>
425
- public static string GetUniqueName ( string prefix , bool withBracket = true )
426
- {
427
- string escapeLeft = withBracket ? "[" : string . Empty ;
428
- string escapeRight = withBracket ? "]" : string . Empty ;
429
- string uniqueName = string . Format ( "{0}{1}_{2}_{3}{4}" ,
430
- escapeLeft ,
431
- prefix ,
432
- DateTime . Now . Ticks . ToString ( "X" , CultureInfo . InvariantCulture ) , // up to 8 characters
433
- Guid . NewGuid ( ) . ToString ( ) . Substring ( 0 , 6 ) , // take the first 6 characters only
434
- escapeRight ) ;
435
- return uniqueName ;
455
+ ///
456
+ /// <param name="prefix">
457
+ /// The prefix to use when generating the unique name, truncated to at
458
+ /// most 18 characters when withBracket is false, and 16 characters when
459
+ /// withBracket is true.
460
+ ///
461
+ /// This should not contain any characters that cannot be used in
462
+ /// database object names. See:
463
+ ///
464
+ /// https://learn.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers?view=sql-server-ver17#rules-for-regular-identifiers
465
+ /// </param>
466
+ ///
467
+ /// <param name="withBracket">
468
+ /// When true, the entire generated name will be enclosed in square
469
+ /// brackets, for example:
470
+ ///
471
+ /// [MyPrefix_7ff01cb811f0]
472
+ /// </param>
473
+ ///
474
+ /// <returns>
475
+ /// A unique database object name, no more than 30 characters long.
476
+ /// </returns>
477
+ public static string GetShortName ( string prefix , bool withBracket = true )
478
+ {
479
+ StringBuilder name = new ( 30 ) ;
480
+
481
+ if ( withBracket )
482
+ {
483
+ name . Append ( '[' ) ;
484
+ }
485
+
486
+ int maxPrefixLength = withBracket ? 16 : 18 ;
487
+ if ( prefix . Length > maxPrefixLength )
488
+ {
489
+ prefix = prefix . Substring ( 0 , maxPrefixLength ) ;
490
+ }
491
+
492
+ name . Append ( prefix ) ;
493
+ name . Append ( '_' ) ;
494
+ name . Append ( GetGuidParts ( ) ) ;
495
+
496
+ if ( withBracket )
497
+ {
498
+ name . Append ( ']' ) ;
499
+ }
500
+
501
+ return name . ToString ( ) ;
436
502
}
437
503
438
504
/// <summary>
439
- /// Uses environment values `UserName` and `MachineName` in addition to the specified `prefix` and current date
440
- /// to generate a unique name to use in Sql Server;
441
- /// SQL Server supports long names (up to 128 characters), add extra info for troubleshooting.
505
+ /// Generate a long unique database object name, whose maximum length is
506
+ /// 96 characters, with the format:
507
+ ///
508
+ /// <Prefix>_<GuidParts>_<UserName>_<MachineName>
509
+ ///
510
+ /// The Prefix will be truncated to satisfy the overall maximum length.
511
+ ///
512
+ /// The GUID Parts will be the characters from the 1st and 4th blocks
513
+ /// from a traditional string representation, as shown here:
514
+ ///
515
+ /// 7ff01cb8-88c7-11f0-b433-00155d7e531e
516
+ /// ^^^^^^^^ ^^^^
517
+ ///
518
+ /// These 2 parts typically comprise a timestamp and clock sequence,
519
+ /// most likely to be unique for tests that generate names in quick
520
+ /// succession. The 12 characters are concatenated together without any
521
+ /// separators.
522
+ ///
523
+ /// The UserName and MachineName are obtained from the Environment,
524
+ /// and will be truncated to satisfy the maximum overall length.
442
525
/// </summary>
443
- /// <param name="prefix">Add the prefix to the generate string.</param>
444
- /// <param name="withBracket">Database name must be pass with brackets by default.</param>
445
- /// <returns>Unique name by considering the Sql Server naming rules, never longer than 96 characters.</returns>
446
- public static string GetUniqueNameForSqlServer ( string prefix , bool withBracket = true )
447
- {
448
- string extendedPrefix = string . Format (
449
- "{0}_{1}_{2}@{3}" ,
450
- prefix ,
451
- Environment . UserName ,
452
- Environment . MachineName ,
453
- DateTime . Now . ToString ( "yyyy_MM_dd" , CultureInfo . InvariantCulture ) ) ;
454
- string name = GetUniqueName ( extendedPrefix , withBracket ) ;
455
-
456
- // Truncate to no more than 96 characters.
457
- const int maxLen = 96 ;
458
- if ( name . Length > maxLen )
459
- {
460
- if ( withBracket )
461
- {
462
- name = name . Substring ( 0 , maxLen - 1 ) + ']' ;
463
- }
464
- else
465
- {
466
- name = name . Substring ( 0 , maxLen ) ;
467
- }
526
+ ///
527
+ /// <param name="prefix">
528
+ /// The prefix to use when generating the unique name, truncated to at
529
+ /// most 32 characters.
530
+ ///
531
+ /// This should not contain any characters that cannot be used in
532
+ /// database object names. See:
533
+ ///
534
+ /// https://learn.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers?view=sql-server-ver17#rules-for-regular-identifiers
535
+ /// </param>
536
+ ///
537
+ /// <param name="withBracket">
538
+ /// When true, the entire generated name will be enclosed in square
539
+ /// brackets, for example:
540
+ ///
541
+ /// [MyPrefix_7ff01cb811f0_test_user_ci_agent_machine_name]
542
+ /// </param>
543
+ ///
544
+ /// <returns>
545
+ /// A unique database object name, no more than 96 characters long.
546
+ /// </returns>
547
+ public static string GetLongName ( string prefix , bool withBracket = true )
548
+ {
549
+ StringBuilder name = new ( 96 ) ;
550
+
551
+ if ( withBracket )
552
+ {
553
+ name . Append ( '[' ) ;
554
+ }
555
+
556
+ if ( prefix . Length > 32 )
557
+ {
558
+ prefix = prefix . Substring ( 0 , 32 ) ;
559
+ }
560
+
561
+ name . Append ( prefix ) ;
562
+ name . Append ( '_' ) ;
563
+ name . Append ( GetGuidParts ( ) ) ;
564
+ name . Append ( '_' ) ;
565
+
566
+ var suffix =
567
+ Environment . UserName + '_' +
568
+ Environment . MachineName ;
569
+
570
+ int maxSuffixLength = 96 - name . Length ;
571
+ if ( withBracket )
572
+ {
573
+ -- maxSuffixLength ;
574
+ }
575
+ if ( suffix . Length > maxSuffixLength )
576
+ {
577
+ suffix = suffix . Substring ( 0 , maxSuffixLength ) ;
578
+ }
579
+
580
+ name . Append ( suffix ) ;
581
+
582
+ if ( withBracket )
583
+ {
584
+ name . Append ( ']' ) ;
468
585
}
469
586
470
- return name ;
587
+ return name . ToString ( ) ;
471
588
}
472
589
473
590
public static bool IsSupportingDistributedTransactions ( )
0 commit comments