A Syntax Mystery in a Previously Working Procedure

,

I once had a need to amend a procedure used by a report. The purpose was to enhance the report to have more fields displayed. My solution was straightforward: change the procedure logic to include the new fields, drop and recreate the procedure, and update the report file to include the added fields.

I was astonished to find that the procedure had syntax errors even before I started changing it. I tried to run the report with the original procedure in place and found the report was working fine. At this point I was confused with two main questions in my mind. One was how is the procedure working while it has syntax errors, and two, how did the first programmer manage to create the procedure and get it installed with the errors.

On my effort to solve the issue, I gained knowledge and experience that I want to share with others. I hope I can help others who may encounter the same problem and prevent them from spending a large amount of time diagnosing the issue.

The Actual Problem

Let us go to the actual problem that we need to address. I am using the AdventureWorks2012 database for my explanation. Run the code in LIsting 1 to create the procedure that we are going to use.

USE AdventureWorks2012;
GO
DECLARE @String NVARCHAR(MAX);
--Generate a string for creating a procedure
SET @String = 'CREATE PROCEDURE cProcWithLongStrings AS SELECT ' + char(39)
+ REPLICATE ('A',200) + char (39) + ' as First,'
+ char(39) + REPLICATE('B',243) + char(39) + ' as Secon,'
+ char(39) + REPLICATE('C',243) + char(39) + ' as Third,'
+ char(39) + REPLICATE('D',243) + char(39) + ' as Fourt,'
+ char(39) + REPLICATE('E',243) + char(39) + ' as Fifth;';
--Getting the script for creating the procedure
PRINT @String
--Install the procedure by executing the string.
EXEC (@String );
GO

Listing 1

Below is the result as seen in Management Studio 

Figure 1

Now we have our procedure created, we need to have a print result for the string used to create the procedure. This string is going to be stored in the text column of the sys.syscomments table. Let us find the length of the string. We can do that by copying the string to the word count application like charactercountonline.

Below is the copy of the print result

CREATE PROCEDURE cProcWithLongStrings
AS
SELECT
  'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' as First
, 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB' as Secon
, 'CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC' as Third
, 'DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD' as Fourth
, 'EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE' as Fifth;

Listing 2

You will find that the count is 1280 characters as seen in the screen shot below.

Figure 2

Now let us execute the script to see the result

EXECUTE cProcWithLongStrings;

Upon executing the above statement we get the results shown in Figure 3.

Figure 3

The result above means that our procedure is working correctly, since the procedure run without errors and gave the expected output.

Now let us get the text for our procedure, which we will use to recreate the procedure. To do that we run the following code:

--Getting the created procedure using sp_helptext
EXEC sp_helptext 'cProcWithLongStrings';
GO

Below (in Listing 3) is the result that you will get after running the code above

CREATE PROCEDURE cProcWithLongStrings AS SELECT'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' as F
irst,'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB' as S
econd,'CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC' as T
hird,'DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD' as F
ourth,'EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE' as F
ifth;

Listing 3

In a new code window run the following code to drop the cProcWithLongString procedure.

DROP PROCEDURE cProcWithLongStrings
GO 

Go back to the code window with results shown in listing 3 and run the code to recreate the cProcWithLongStringprocedure.

Upon recreating the procedure you will get the following error.

Msg 102, Level 15, State 1, Procedure cProcWithLongStrings, Line 2

Incorrect syntax near 'irst'.

If we look at the text output of the code in Listing 1 we can see that the whole procedure is only in one line with no syntax errors as seen in Figure 1.  Using sp_helptext to recreate the procedure text from syscomments resulted to a procedure with syntax errors. This is because of algorithms used by sp_helptext to do its job. sp_helptext reads text from syscomments and appends a new line after every 255th character. In our procedure the first 255th character if F of the word first, and the second 255th character is S of the word second. The third 255th character is T of the word third, the fourth 255th character is F of the word fourth, and the last 255th character is F of the word fifth. Thus sp_helptext separated those word (in such a way that they read as F irst, S econd, T hird, F ourth, and F ifth) creating a syntax error since compiler do not accept white spaces for columns map names. 

To workaround this problem you can remove the white spaces introduced by sp_helptext to form complete words. Sometimes this approach can be tedious if we have a complex procedure or if this problem is occurring frequently. In that case is better to have a separate copy of sp_helptext which do not append a new line after each 255th character.

Let us have a look on sp_helptext procedure to understand which change is needed to achieve that. Run the code below to get the procedure

sp_helptext sp_helptext

Below is the output of the query above

create procedure sys. sp_helptext
@objname nvarchar (776)
,@columnname sysname = NULL
as
set nocount on
declare @dbname sysname
,@objid       int
,@BlankSpaceAdded   int
,@BasePos       int
,@CurrentPos    int
,@TextLength    int
,@LineId        int
,@AddOnLen      int
,@LFCR          int --lengths of line feed carriage return
,@DefinedLength int
/* NOTE: Length of @SyscomText is 4000 to replace the length of
** text column in syscomments.
** lengths on @Line, #CommentText Text column and
** value for @DefinedLength are all 255. These need to all have
** the same values. 255 was selected in order for the max length
** display using down level clients
*/
,@SyscomText  nvarchar(4000 )
,@Line          nvarchar(255 )
select @DefinedLength = 255
select @BlankSpaceAdded = 0 /*Keeps track of blank spaces at end of lines. Note Len function ignores
                             trailing blank spaces*/
CREATE TABLE #CommentText
(LineId       int
 ,Text   nvarchar( 255) collate catalog_default )
/*
**  Make sure the @objname is local to the current database.
*/
select @dbname = parsename(@objname ,3)
if @dbname is null
        select @dbname = db_name()
else if @dbname <> db_name ()
        begin
                raiserror(15250 ,-1,- 1)
                return (1 )
        end
/*
**  See if @objname exists.
*/
select @objid = object_id(@objname )
if (@objid is null)
        begin
              raiserror(15009 ,-1,- 1,@objname ,@dbname)
              return (1 )
        end
-- If second parameter was given.
if ( @columnname is not null)
    begin
        -- Check if it is a table
        if (select count(*) from sys.objects where object_id = @objid and type in ( 'S ','U ' ,'TF'))= 0
            begin
                raiserror(15218 ,-1,- 1,@objname )
                return(1 )
            end
        -- check if it is a correct column name
        if ((select 'count'= count(*) from sys .columns where name = @columnname and object_id = @objid) =0)
            begin
                raiserror(15645 ,-1,- 1,@columnname )
                return(1 )
            end
    if ( ColumnProperty(@objid , @columnname , 'IsComputed' ) = 0)
              begin
                     raiserror(15646 ,-1,- 1,@columnname )
                     return(1 )
              end
        declare ms_crs_syscom   CURSOR LOCAL
        FOR select text from syscomments where id = @objid and encrypted = 0 and number =
                        (select column_id from sys. columns where name = @columnname and object_id = @objid )
                        order by number, colid
        FOR READ ONLY
    end
else if @objid < 0  -- Handle system-objects
        begin
              -- Check count of rows with text data
              if (select count(*) from master.sys .syscomments where id = @objid and text is not null) = 0
                     begin
                            raiserror(15197 ,-1,- 1,@objname )
                            return (1 )
                     end
                    
              declare ms_crs_syscom CURSOR LOCAL FOR select text from master.sys .syscomments where id = @objid
                     ORDER BY number, colid FOR READ ONLY
        end
else
    begin
        /*
        **  Find out how many lines of text are coming back,
        **  and return if there are none.
        */
        if (select count(*) from syscomments c , sysobjects o where o .xtype not in ( 'S', 'U')
            and o .id = c .id and o .id = @objid ) = 0
                begin
                        raiserror(15197 ,-1,- 1,@objname )
                        return (1 )
                end
        if (select count(*) from syscomments where id = @objid and encrypted = 0) = 0
                begin
                        raiserror(15471 ,-1,- 1,@objname )
                        return (0 )
                end
              declare ms_crs_syscom   CURSOR LOCAL
              FOR select text from syscomments where id = @objid and encrypted = 0
                            ORDER BY number, colid
              FOR READ ONLY
    end
/*
**  else get the text.
*/
select @LFCR = 2
select @LineId = 1

OPEN ms_crs_syscom
FETCH NEXT from ms_crs_syscom into @SyscomText
WHILE @@fetch_status >= 0
begin
    select  @BasePos    = 1
   select  @CurrentPos = 1
    select  @TextLength = LEN( @SyscomText)
    WHILE @CurrentPos  != 0
    begin
        --Looking for end of line followed by carriage return
        select @CurrentPos =   CHARINDEX(char (13)+ char(10 ), @SyscomText , @BasePos)
        --If carriage return found
        IF @CurrentPos != 0
        begin
            /*If new value for @Lines length will be > then the
            **set length then insert current contents of @line
            **and proceed.
            */
            while (isnull (LEN( @Line),0 ) + @BlankSpaceAdded + @CurrentPos-@BasePos + @LFCR) > @DefinedLength
            begin
                select @AddOnLen = @DefinedLength-(isnull (LEN( @Line),0 ) + @BlankSpaceAdded)
                INSERT #CommentText VALUES
                ( @LineId ,
                  isnull(@Line , N'' ) + isnull( SUBSTRING(@SyscomText , @BasePos , @AddOnLen), N''))
                select @Line = NULL, @LineId = @LineId + 1,
                       @BasePos = @BasePos + @AddOnLen , @BlankSpaceAdded = 0
            end
            select @Line     = isnull(@Line , N'' ) + isnull( SUBSTRING(@SyscomText , @BasePos, @CurrentPos-@BasePos + @LFCR), N'')
            select @BasePos = @CurrentPos+2
            INSERT #CommentText VALUES( @LineId, @Line )
            select @LineId = @LineId + 1
            select @Line = NULL
        end
        else
        --else carriage return not found
        begin
            IF @BasePos <= @TextLength
            begin
                /*If new value for @Lines length will be > then the
                **defined length
                */
                while (isnull (LEN( @Line),0 ) + @BlankSpaceAdded + @TextLength-@BasePos +1 ) > @DefinedLength
                begin
                    select @AddOnLen = @DefinedLength - (isnull (LEN( @Line),0 ) + @BlankSpaceAdded)
                    INSERT #CommentText VALUES
                    ( @LineId ,
                      isnull(@Line , N'' ) + isnull( SUBSTRING(@SyscomText , @BasePos, @AddOnLen), N''))
                    select @Line = NULL, @LineId = @LineId + 1,
                        @BasePos = @BasePos + @AddOnLen , @BlankSpaceAdded = 0
                end
                select @Line = isnull(@Line , N'' ) + isnull(SUBSTRING (@SyscomText, @BasePos, @TextLength- @BasePos+1 ), N'' )
                if LEN (@Line) < @DefinedLength and charindex( ' ', @SyscomText, @TextLength+1 ) > 0
                begin
                    select @Line = @Line + ' ', @BlankSpaceAdded = 1
                end
            end
        end
    end
        FETCH NEXT from ms_crs_syscom into @SyscomText
end
IF @Line is NOT NULL
    INSERT #CommentText VALUES ( @LineId , @Line )
select Text from #CommentText order by LineId
CLOSE  ms_crs_syscom
DEALLOCATE   ms_crs_syscom
DROP TABLE   #CommentText
return (0 ) -- sp_helptext

Listing 4

I will explain only some part of this procedure, you can take your own time to understand it better. From the top of the procedure you can see that there is number of declaration of variables. To achieve our goal we need to change length for @Line and value @DefinedLength parameters from 255 to 4000. @Line is the parameter that holds the lines of the printed output from sp_helptext. @DefinedLength is a parameter that  holds maximum span length of the printed output from sp_helptext, this is why you can see the result from sp_helptext cProcWithLongStrings span to that length. @DefinedLength is used by the procedure to calculate the length of line to be printed out. We also need to change the length of Text field in #CommentText table to 4000.

Now go on and do the changes, also rename the procedure from sys.sp_helptext to dbo.custom_sp_helptext. Our new procedure will be this.

create procedure dbo. custom_sp_helptext
@objname nvarchar (776)
,@columnname sysname = NULL
as
set nocount on
declare @dbname sysname
,@objid       int
,@BlankSpaceAdded   int
,@BasePos       int
,@CurrentPos    int
,@TextLength    int
,@LineId        int
,@AddOnLen      int
,@LFCR          int --lengths of line feed carriage return
,@DefinedLength int
/* NOTE: Length of @SyscomText is 4000 to replace the length of
** text column in syscomments.
** lengths on @Line, #CommentText Text column and
** value for @DefinedLength are all 255. These need to all have
** the same values. 255 was selected in order for the max length
** display using down level clients
*/
,@SyscomText  nvarchar(4000 )
,@Line          nvarchar(4000 )
select @DefinedLength = 4000
select @BlankSpaceAdded = 0 /*Keeps track of blank spaces at end of lines. Note Len function ignores
                             trailing blank spaces*/
CREATE TABLE #CommentText
(LineId       int
 ,Text   nvarchar( 4000) collate catalog_default )
/*
**  Make sure the @objname is local to the current database.
*/
select @dbname = parsename(@objname ,3)
if @dbname is null
        select @dbname = db_name()
else if @dbname <> db_name ()
        begin
                raiserror(15250 ,-1,- 1)
                return (1 )
        end
/*
**  See if @objname exists.
*/
select @objid = object_id(@objname )
if (@objid is null)
        begin
              raiserror(15009 ,-1,- 1,@objname ,@dbname)
              return (1 )
        end
-- If second parameter was given.
if ( @columnname is not null)
    begin
        -- Check if it is a table
        if (select count(*) from sys.objects where object_id = @objid and type in ( 'S ','U ' ,'TF'))= 0
            begin
                raiserror(15218 ,-1,- 1,@objname )
                return(1 )
            end
        -- check if it is a correct column name
        if ((select 'count'= count(*) from sys .columns where name = @columnname and object_id = @objid) =0)
            begin
                raiserror(15645 ,-1,- 1,@columnname )
                return(1 )
            end
    if ( ColumnProperty(@objid , @columnname , 'IsComputed' ) = 0)
              begin
                     raiserror(15646 ,-1,- 1,@columnname )
                     return(1 )
              end
        declare ms_crs_syscom   CURSOR LOCAL
        FOR select text from syscomments where id = @objid and encrypted = 0 and number =
                        (select column_id from sys. columns where name = @columnname and object_id = @objid )
                        order by number, colid
        FOR READ ONLY
    end
else if @objid < 0  -- Handle system-objects
        begin
              -- Check count of rows with text data
              if (select count(*) from master.sys .syscomments where id = @objid and text is not null) = 0
                     begin
                            raiserror(15197 ,-1,- 1,@objname )
                            return (1 )
                     end
                    
              declare ms_crs_syscom CURSOR LOCAL FOR select text from master.sys .syscomments where id = @objid
                     ORDER BY number, colid FOR READ ONLY
        end
else
    begin
        /*
        **  Find out how many lines of text are coming back,
        **  and return if there are none.
        */
        if (select count(*) from syscomments c , sysobjects o where o .xtype not in ( 'S', 'U')
            and o .id = c .id and o .id = @objid ) = 0
                begin
                        raiserror(15197 ,-1,- 1,@objname )
                        return (1 )
                end
        if (select count(*) from syscomments where id = @objid and encrypted = 0) = 0
                begin
                        raiserror(15471 ,-1,- 1,@objname )
                        return (0 )
                end
              declare ms_crs_syscom   CURSOR LOCAL
              FOR select text from syscomments where id = @objid and encrypted = 0
                            ORDER BY number, colid
              FOR READ ONLY
    end
/*
**  else get the text.
*/
select @LFCR = 2
select @LineId = 1
OPEN ms_crs_syscom
FETCH NEXT from ms_crs_syscom into @SyscomText
WHILE @@fetch_status >= 0
begin
   select  @BasePos    = 1
   select  @CurrentPos = 1
   select  @TextLength = LEN( @SyscomText)
    WHILE @CurrentPos  != 0
    begin
        --Looking for end of line followed by carriage return
        select @CurrentPos =   CHARINDEX(char (13)+ char(10 ), @SyscomText , @BasePos)
        --If carriage return found
        IF @CurrentPos != 0
        begin
            /*If new value for @Lines length will be > then the
            **set length then insert current contents of @line
            **and proceed.
            */
            while (isnull (LEN( @Line),0 ) + @BlankSpaceAdded + @CurrentPos-@BasePos + @LFCR) > @DefinedLength
            begin
                select @AddOnLen = @DefinedLength-(isnull (LEN( @Line),0 ) + @BlankSpaceAdded)
                INSERT #CommentText VALUES
                ( @LineId ,
                  isnull(@Line , N'' ) + isnull( SUBSTRING(@SyscomText , @BasePos , @AddOnLen), N''))
                select @Line = NULL, @LineId = @LineId + 1,
                       @BasePos = @BasePos + @AddOnLen , @BlankSpaceAdded = 0
            end
            select @Line     = isnull(@Line , N'' ) + isnull( SUBSTRING(@SyscomText , @BasePos, @CurrentPos-@BasePos + @LFCR), N'')
            select @BasePos = @CurrentPos+2
            INSERT #CommentText VALUES( @LineId, @Line )
            select @LineId = @LineId + 1
            select @Line = NULL
        end
        else
        --else carriage return not found
        begin
            IF @BasePos <= @TextLength
            begin
                /*If new value for @Lines length will be > then the
                **defined length
                */
                while (isnull (LEN( @Line),0 ) + @BlankSpaceAdded + @TextLength-@BasePos +1 ) > @DefinedLength
                begin
                    select @AddOnLen = @DefinedLength - (isnull (LEN( @Line),0 ) + @BlankSpaceAdded)
                    INSERT #CommentText VALUES
                    ( @LineId ,
                      isnull(@Line , N'' ) + isnull( SUBSTRING(@SyscomText , @BasePos, @AddOnLen), N''))
                    select @Line = NULL, @LineId = @LineId + 1,
                        @BasePos = @BasePos + @AddOnLen , @BlankSpaceAdded = 0
                end
                select @Line = isnull(@Line , N'' ) + isnull(SUBSTRING (@SyscomText, @BasePos, @TextLength- @BasePos+1 ), N'' )
                if LEN (@Line) < @DefinedLength and charindex( ' ', @SyscomText, @TextLength+1 ) > 0
                begin
                    select @Line = @Line + ' ', @BlankSpaceAdded = 1
                end
            end
        end
    end
        FETCH NEXT from ms_crs_syscom into @SyscomText
end
IF @Line is NOT NULL
    INSERT #CommentText VALUES ( @LineId , @Line )
select Text from #CommentText order by LineId
CLOSE  ms_crs_syscom
DEALLOCATE   ms_crs_syscom
DROP TABLE   #CommentText
return (0 ) -- sp_helptext
--

Listing 5

Run the procedure and test it to see if we have fixed the problem. It should work now. Let us now rerun our cProcWithLongStrings this new version of sp_helptext.

EXEC custom_sp_helptext 'cProcWithLongStrings'

Now we have a result that do not have syntax errors.

CREATE PROCEDURE [dbo].[cProcWithLongStrings] AS SELECT 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' as First,'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB' as Secon,'CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC' as Third,'DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD' as Fourt,'EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE' as Fifth;

Rate

3.21 (33)

Share

Share

Rate

3.21 (33)