-- copy_text_to_varchar.sql
-- Proc get_text does READTEXT in a loop to read chunks of text
-- no larger than 200, or the column size or @@TEXTSIZE, and
-- produces as many rows as necessary to store the text column
-- as a series of sequenced varchar(200) rows
CREATE PROC get_text @pub_id char(4)
AS
DECLARE @mytextptr varbinary(16), @totalsize int, @lastread int,
@readsize int
-- Use a TRAN and HOLDLOCK to ensure that textptr and text are
-- constant during the iterative reads
BEGIN TRAN
SELECT @mytextptr=TEXTPTR(pr_info), @totalsize=DATALENGTH(pr_info),
@lastread=0,
-- Set the readsize to the smaller of the @@TEXTSIZE settings,
-- 200, and the total length of the column
@readsize=CASE WHEN (200 < DATALENGTH(pr_info)) THEN 200
ELSE DATALENGTH(pr_info) END
FROM pub_info (HOLDLOCK) WHERE pub_id=@pub_id
-- If debugging, uncomment this to check values
-- SELECT @mytextptr, @totalsize, @lastread, @readsize
-- Do READTEXT in a loop to get next 200 characters until done
IF @mytextptr IS NOT NULL AND @readsize > 0
WHILE (@lastread < @totalsize)
BEGIN
-- If readsize would go beyond end, adjust readsize
IF ((@readsize + @lastread) > @totalsize)
SELECT @readsize = @totalsize - @lastread
-- If debugging, uncomment this to check values
-- SELECT 'valid ptr?'=textvalid('pub_info.pr_info',
-- @mytextptr), 'totalsize'=@totalsize,
-- 'lastread'=@lastread, 'readsize'=@readsize
READTEXT pub_info.pr_info @mytextptr @lastread @readsize
IF (@@ERROR <> 0)
BREAK -- Break out of loop if an error on read
-- Change offset to last char read
SELECT @lastread=@lastread + @readsize
END
COMMIT TRAN
GO
IF EXISTS (SELECT * FROM tempdb.dbo.sysobjects
WHERE name='##mytmptext' AND type='U')
DROP TABLE ##mytmptext
GO
-- Intermediate temp table that READTEXT will use.
-- This table is truncated after each pub_id value, so the Identity
-- property sequences the rows for each publisher separately.
CREATE TABLE ##mytmptext
(
seq_no int IDENTITY,
text_chunk text
)
GO
IF EXISTS (SELECT * FROM sysobjects
WHERE name='newprinfo' AND type='U')
DROP TABLE newprinfo
GO
-- This is the new table that pub_info is copied to.
-- It keeps chunks of text and is sequenced for each pub_id.
CREATE TABLE newprinfo
(
pub_id char(4) NOT NULL,
seq_no int NOT NULL,
text_chunk varchar(200),
CONSTRAINT PK PRIMARY KEY (pub_id, seq_no)
)
GO
-- Having created the procedure get_text, iterate for each pub_id
-- value, temporarily sequencing them in the temp table. Once done
-- for a given pub_id, copy them to the new permanent table. Then
-- truncate the temp table for use with reseeded Identity for next
-- pub_id row.
DECLARE @pub_id char(4)
DECLARE iterate_prinfo CURSOR FOR
SELECT pub_id FROM pub_info ORDER BY pub_id
OPEN iterate_prinfo
FETCH NEXT FROM iterate_prinfo INTO @pub_id
BEGIN
TRUNCATE TABLE ##mytmptext
INSERT ##mytmptext
EXEC get_text @pub_id
INSERT newprinfo (pub_id, seq_no, text_chunk)
SELECT @pub_id, SEQ_NO,
CONVERT(varchar(200), TEXT_CHUNK)
FROM ##mytmptext ORDER BY SEQ_NO
FETCH NEXT FROM iterate_prinfo INTO @pub_id
END
CLOSE iterate_prinfo
DEALLOCATE iterate_prinfo
GO
-- Simply verify contents of the new table
SELECT * FROM newprinfo ORDER BY pub_id,seq_no
GO