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