@@ -117,7 +117,7 @@ public static bool TcpConnectionStringDoesNotUseAadAuth
117
117
{
118
118
get
119
119
{
120
- SqlConnectionStringBuilder builder = new ( TCPConnectionString ) ;
120
+ SqlConnectionStringBuilder builder = new ( TCPConnectionString ) ;
121
121
return builder . Authentication == SqlAuthenticationMethod . SqlPassword || builder . Authentication == SqlAuthenticationMethod . NotSpecified ;
122
122
}
123
123
}
@@ -546,59 +546,176 @@ public static bool DoesHostAddressContainBothIPv4AndIPv6()
546
546
}
547
547
}
548
548
549
+ // Generate a new GUID and return the characters from its 1st and 4th
550
+ // parts, as shown here:
551
+ //
552
+ // 7ff01cb8-88c7-11f0-b433-00155d7e531e
553
+ // ^^^^^^^^ ^^^^
554
+ //
555
+ // These 12 characters are concatenated together without any
556
+ // separators. These 2 parts typically comprise a timestamp and clock
557
+ // sequence, most likely to be unique for tests that generate names in
558
+ // quick succession.
559
+ private static string GetGuidParts ( )
560
+ {
561
+ var guid = Guid . NewGuid ( ) . ToString ( ) ;
562
+ // GOTCHA: The slice operator is inclusive of the start index and
563
+ // exclusive of the end index!
564
+ return guid . Substring ( 0 , 8 ) + guid . Substring ( 19 , 4 ) ;
565
+ }
566
+
549
567
/// <summary>
550
- /// Generate a unique name to use in Sql Server;
551
- /// some providers does not support names (Oracle supports up to 30).
568
+ /// Generate a short unique database object name, whose maximum length
569
+ /// is 30 characters, with the format:
570
+ ///
571
+ /// <Prefix>_<GuidParts>
572
+ ///
573
+ /// The Prefix will be truncated to satisfy the overall maximum length.
574
+ ///
575
+ /// The GUID parts will be the characters from the 1st and 4th blocks
576
+ /// from a traditional string representation, as shown here:
577
+ ///
578
+ /// 7ff01cb8-88c7-11f0-b433-00155d7e531e
579
+ /// ^^^^^^^^ ^^^^
580
+ ///
581
+ /// These 2 parts typically comprise a timestamp and clock sequence,
582
+ /// most likely to be unique for tests that generate names in quick
583
+ /// succession. The 12 characters are concatenated together without any
584
+ /// separators.
552
585
/// </summary>
553
- /// <param name="prefix">The name length will be no more then (16 + prefix.Length + escapeLeft.Length + escapeRight.Length).</param>
554
- /// <param name="withBracket">Name without brackets.</param>
555
- /// <returns>Unique name by considering the Sql Server naming rules.</returns>
556
- public static string GetUniqueName ( string prefix , bool withBracket = true )
557
- {
558
- string escapeLeft = withBracket ? "[" : string . Empty ;
559
- string escapeRight = withBracket ? "]" : string . Empty ;
560
- string uniqueName = string . Format ( "{0}{1}_{2}_{3}{4}" ,
561
- escapeLeft ,
562
- prefix ,
563
- DateTime . Now . Ticks . ToString ( "X" , CultureInfo . InvariantCulture ) , // up to 8 characters
564
- Guid . NewGuid ( ) . ToString ( ) . Substring ( 0 , 6 ) , // take the first 6 characters only
565
- escapeRight ) ;
566
- return uniqueName ;
586
+ ///
587
+ /// <param name="prefix">
588
+ /// The prefix to use when generating the unique name, truncated to at
589
+ /// most 18 characters when withBracket is false, and 16 characters when
590
+ /// withBracket is true.
591
+ ///
592
+ /// This should not contain any characters that cannot be used in
593
+ /// database object names. See:
594
+ ///
595
+ /// https://learn.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers?view=sql-server-ver17#rules-for-regular-identifiers
596
+ /// </param>
597
+ ///
598
+ /// <param name="withBracket">
599
+ /// When true, the entire generated name will be enclosed in square
600
+ /// brackets, for example:
601
+ ///
602
+ /// [MyPrefix_7ff01cb811f0]
603
+ /// </param>
604
+ ///
605
+ /// <returns>
606
+ /// A unique database object name, no more than 30 characters long.
607
+ /// </returns>
608
+ public static string GetShortName ( string prefix , bool withBracket = true )
609
+ {
610
+ StringBuilder name = new ( 30 ) ;
611
+
612
+ if ( withBracket )
613
+ {
614
+ name . Append ( '[' ) ;
615
+ }
616
+
617
+ int maxPrefixLength = withBracket ? 16 : 18 ;
618
+ if ( prefix . Length > maxPrefixLength )
619
+ {
620
+ prefix = prefix . Substring ( 0 , maxPrefixLength ) ;
621
+ }
622
+
623
+ name . Append ( prefix ) ;
624
+ name . Append ( '_' ) ;
625
+ name . Append ( GetGuidParts ( ) ) ;
626
+
627
+ if ( withBracket )
628
+ {
629
+ name . Append ( ']' ) ;
630
+ }
631
+
632
+ return name . ToString ( ) ;
567
633
}
568
634
569
635
/// <summary>
570
- /// Uses environment values `UserName` and `MachineName` in addition to the specified `prefix` and current date
571
- /// to generate a unique name to use in Sql Server;
572
- /// SQL Server supports long names (up to 128 characters), add extra info for troubleshooting.
636
+ /// Generate a long unique database object name, whose maximum length is
637
+ /// 96 characters, with the format:
638
+ ///
639
+ /// <Prefix>_<GuidParts>_<UserName>_<MachineName>
640
+ ///
641
+ /// The Prefix will be truncated to satisfy the overall maximum length.
642
+ ///
643
+ /// The GUID Parts will be the characters from the 1st and 4th blocks
644
+ /// from a traditional string representation, as shown here:
645
+ ///
646
+ /// 7ff01cb8-88c7-11f0-b433-00155d7e531e
647
+ /// ^^^^^^^^ ^^^^
648
+ ///
649
+ /// These 2 parts typically comprise a timestamp and clock sequence,
650
+ /// most likely to be unique for tests that generate names in quick
651
+ /// succession. The 12 characters are concatenated together without any
652
+ /// separators.
653
+ ///
654
+ /// The UserName and MachineName are obtained from the Environment,
655
+ /// and will be truncated to satisfy the maximum overall length.
573
656
/// </summary>
574
- /// <param name="prefix">Add the prefix to the generate string.</param>
575
- /// <param name="withBracket">Database name must be pass with brackets by default.</param>
576
- /// <returns>Unique name by considering the Sql Server naming rules, never longer than 96 characters.</returns>
577
- public static string GetUniqueNameForSqlServer ( string prefix , bool withBracket = true )
578
- {
579
- string extendedPrefix = string . Format (
580
- "{0}_{1}_{2}@{3}" ,
581
- prefix ,
582
- Environment . UserName ,
583
- Environment . MachineName ,
584
- DateTime . Now . ToString ( "yyyy_MM_dd" , CultureInfo . InvariantCulture ) ) ;
585
- string name = GetUniqueName ( extendedPrefix , withBracket ) ;
586
-
587
- // Truncate to no more than 96 characters.
588
- const int maxLen = 96 ;
589
- if ( name . Length > maxLen )
590
- {
591
- if ( withBracket )
592
- {
593
- name = name . Substring ( 0 , maxLen - 1 ) + ']' ;
594
- }
595
- else
596
- {
597
- name = name . Substring ( 0 , maxLen ) ;
598
- }
657
+ ///
658
+ /// <param name="prefix">
659
+ /// The prefix to use when generating the unique name, truncated to at
660
+ /// most 32 characters.
661
+ ///
662
+ /// This should not contain any characters that cannot be used in
663
+ /// database object names. See:
664
+ ///
665
+ /// https://learn.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers?view=sql-server-ver17#rules-for-regular-identifiers
666
+ /// </param>
667
+ ///
668
+ /// <param name="withBracket">
669
+ /// When true, the entire generated name will be enclosed in square
670
+ /// brackets, for example:
671
+ ///
672
+ /// [MyPrefix_7ff01cb811f0_test_user_ci_agent_machine_name]
673
+ /// </param>
674
+ ///
675
+ /// <returns>
676
+ /// A unique database object name, no more than 96 characters long.
677
+ /// </returns>
678
+ public static string GetLongName ( string prefix , bool withBracket = true )
679
+ {
680
+ StringBuilder name = new ( 96 ) ;
681
+
682
+ if ( withBracket )
683
+ {
684
+ name . Append ( '[' ) ;
685
+ }
686
+
687
+ if ( prefix . Length > 32 )
688
+ {
689
+ prefix = prefix . Substring ( 0 , 32 ) ;
690
+ }
691
+
692
+ name . Append ( prefix ) ;
693
+ name . Append ( '_' ) ;
694
+ name . Append ( GetGuidParts ( ) ) ;
695
+ name . Append ( '_' ) ;
696
+
697
+ var suffix =
698
+ Environment . UserName + '_' +
699
+ Environment . MachineName ;
700
+
701
+ int maxSuffixLength = 96 - name . Length ;
702
+ if ( withBracket )
703
+ {
704
+ -- maxSuffixLength ;
705
+ }
706
+ if ( suffix . Length > maxSuffixLength )
707
+ {
708
+ suffix = suffix . Substring ( 0 , maxSuffixLength ) ;
709
+ }
710
+
711
+ name . Append ( suffix ) ;
712
+
713
+ if ( withBracket )
714
+ {
715
+ name . Append ( ']' ) ;
599
716
}
600
717
601
- return name ;
718
+ return name . ToString ( ) ;
602
719
}
603
720
604
721
public static void DropTable ( SqlConnection sqlConnection , string tableName )
0 commit comments