@@ -88,7 +88,7 @@ public static bool TcpConnectionStringDoesNotUseAadAuth
8888        { 
8989            get 
9090            { 
91-                 SqlConnectionStringBuilder  builder  =  new   ( TCPConnectionString ) ; 
91+                 SqlConnectionStringBuilder  builder  =  new ( TCPConnectionString ) ; 
9292                return  builder . Authentication  ==  SqlAuthenticationMethod . SqlPassword  ||  builder . Authentication  ==  SqlAuthenticationMethod . NotSpecified ; 
9393            } 
9494        } 
@@ -415,59 +415,176 @@ public static bool DoesHostAddressContainBothIPv4AndIPv6()
415415            } 
416416        } 
417417
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+ 
418436        /// <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. 
421454        /// </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 ( ) ; 
436502        } 
437503
438504        /// <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. 
442525        /// </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 ( ']' ) ; 
468585            } 
469586
470-             return  name ; 
587+             return  name . ToString ( ) ; 
471588        } 
472589
473590        public  static bool  IsSupportingDistributedTransactions ( ) 
0 commit comments