@@ -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