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