Subject Problems after converting VARCHAR(10000) to BLOB (3nd try)
Author jasperelzinga
Hello,

A few months ago we decided to convert our memofield from type
VARCHAR(10000) to BLOB SUB_TYPE TEXT. All went well until some of our
customers were having problems with conversions that involve the
deleting of other tables.

After lots of testing I managed to localize the problem and found a
'recipe' to reproduce the error. One record with a memo-column filled
is enough to make firebird crash when I try to delete the
corresponding table. With the following SQL queries I will try to
explain the process.

Create the domains we need (with the incorrect memo-type)
>> CREATE DOMAIN STRING AS VARCHAR(60) CHARACTER SET NONE
>> CREATE DOMAIN TEXT AS VARCHAR(255) CHARACTER SET NONE
>> CREATE DOMAIN MEMO AS VARCHAR(10000) CHARACTER SET NONE

Create the table, this is the actual table we use.
>> CREATE TABLE Correspondentie (id integer, version integer,
deleted integer, mutex integer, lockedby string, id_instantie integer,
id_persoon integer, id_functie integer, id_medewerker integer,
adresblok memo, naam text, telefoon text, fax text, email text, memo
memo, datum integer, betreft text, aanhef text, afsluiting text,
volgnummer text, id_sjabloon integer, id_document integer, kenmerk
text, uw_kenmerk text, datum_aangemaakt integer, datum_gewijzigd integer)

Insert the killer-record. I will show the actual data below because it
is quite large.
>> INSERT INTO Correspondentie VALUES (%s)

Create a temp domain for the memofields.
>> CREATE DOMAIN MEMOTEMP AS BLOB SUB_TYPE TEXT CHARACTER SET NONE

Now, add a temp field to the table to put the memo-field-data in and
remove the old colum. (instead of renaming the column)
>> ALTER TABLE Correspondentie ADD tempmemo MEMOTEMP
>> UPDATE Correspondentie SET tempmemo=memo
>> ALTER TABLE Correspondentie DROP memo
2x, for another memo-field
>> ALTER TABLE Correspondentie ADD tempadresblok MEMOTEMP
>> UPDATE Correspondentie SET tempadresblok=adresblok
>> ALTER TABLE Correspondentie DROP adresblok

The old memo domain isn't used anymore so it can be dropped and
replaced by the new (blob-)type.
>> DROP DOMAIN MEMO
>> CREATE DOMAIN MEMO AS BLOB SUB_TYPE TEXT CHARACTER SET NONE

Do the same thing as above, but now move it back to the column with
the original name.
>> ALTER TABLE Correspondentie ADD memo MEMO
>> UPDATE Correspondentie SET memo=tempmemo
>> ALTER TABLE Correspondentie DROP tempmemo
Again, 2x.
>> ALTER TABLE Correspondentie ADD adresblok MEMO
>> UPDATE Correspondentie SET adresblok=tempadresblok
>> ALTER TABLE Correspondentie DROP tempadresblok

Drop the temp domain because we don't need it anymore.
>> DROP DOMAIN MEMOTEMP

Now... this query will crash!
>> DROP TABLE Correspondentie

It gives the following error:
kinterbasdb.OperationalError: (-902, 'commit: I/O error for file
"C:\\DATABASE-ARM.FDB". Error while trying to read from file. Einde
van bestand is bereikt.\r\n. ')

"Einde van bestand is bereikt." is from my dutch windows and means
"End of file" :)

Some other things I experimented with:
- I tried this without converting, i mean starting out with the memo
as type BLOB and then inserting the record and trying to delete the
table. That doesn't crash, so its not 100% record-data related i think.
- When i insert the data in a working database that already has been
converted from VARCHAR(10000) to BLOB, it does crash!
- I also tried to first clean the table ("DELETE FROM
Correspondentie") and then drop it. Commiting the drop doen't work the
first time but when i run the same script a second time it does drop
the table!

So.. my conclusion.. it seems to me that the database gets kind of
corrupted after my ALTER TABLE rename thingy and after that crashes on
certain data in BLOB fields.

Now.. the killer data, mind that this is a python-string with some
specials chars like the euro!:
killermemo = ' Wijnsma RMT\n\t\tPostbus 57\n\t\t7550 AB
Hengelo\n\n\nVlaardingen, 14 februari 2005\n\n\n\nGeachte heer
Wijnsma,\n\nIk dank u voor uw aanvraag en hebben heb genoegen u onze
vrijblijvende offerte te doen toekomen voor het vervaardigen
van:\n\nObject\t: Glossy magazine (A4)\nFrequentie\t: 10x per
jaar\nOplage\t: 5.000 exemplaren \nOmvang\t: 96 / 104 / 112
pagina\xe2\x80\x99s binnenwerk in 4 pagina\xe2\x80\x99s
omslag\nFormaat\t: 210 x 297 mm per pagina, staand \nBedrukking\t:
geheel in full-colour, aflopend\nPapier\t: binnenwerk = 115 grams
houtvrij gesatineerd mc, gebaseerd op aanmaak\n\t: omslag = 250grams
houtvrij gesatineerd mc\nVeredeling\t: omslag aan buitenzijde voorzien
van glans laminaat\nAfwerking\t: garenloos gebrocheerd of genaaid
gebrocheerd in 4x gerild omslag\nVerpakking\t: handzaam in
dozen\nOpmaak\t: door ons uit te voeren aan de hand van door u aan te
leveren digitale tekstbestanden\n\t: (word-documenten), digitale
foto\xe2\x80\x99s (jpeg/tiff), digitale logo\xe2\x80\x99s (eps) en
compleet\n\t: opgemaakte digitale commerciele advertenties (hi-res
pdf/quark x-press), \n\t: een en ander uitgevoerd in een nader te
bepalen stramien/uitvoering\nLevertijd\t: in nader
overleg\nTransport\t: franco 1 adres in Nederland in 1
zending\n\t\t\t\nPrijs drukwerk\t: 5.000 exemplaren
\t\tgarenloos\tgenaaid \n\t\t: 96 + 4
pagina\xe2\x80\x99s\t\t\xe2\x82\xac 9.913,00\t\xe2\x82\xac
11.310,00\n\t\t: 104 + 4 pagina\xe2\x80\x99s\t\t\xe2\x82\xac
10.793,00\t\xe2\x82\xac 12.242,00\n\t\t: 112 + 4
pagina\xe2\x80\x99s\t\t\xe2\x82\xac 11.184,00\t\xe2\x82\xac
12.668,00\n\nPrijs opmaak\t: \xe2\x82\xac 50,00 per pagina\nDigitale
aanlevering\t: \xe2\x82\xac 9,50 per pagina voor Certified
PDF\n\nAdv.Acquisitie\t: door u aan te leveren of door ons te
verzorgen tegen 50% provisie\n\nRedactie\t: door u aan te leveren of
door ons uit te voeren tegen een tarief van \xe2\x82\xac 250,00 tot
\n\t\t: \xe2\x82\xac 400,00 per artikel/pagina\n\nPromotie\t: wij
stellen voor om de promotie van dit magazine te doen middels
commercials op\n\t\t: lokale radio en televisie al dan niet
ondersteund door een gerichte mailing aan een, \n\t\t: in overleg met
u, nader te bepalen doelgroep \n\t\t: kosten voor deze promotie zijn
na overleg met u nader te
bepalen\n\n\n\n\n\n\n\n\n\nRekenvoorbeeld:\n\nAls voorbeeld neem ik
het tarief van 112 + 4 pagina\xe2\x80\x99s, genaaid, 5.000 exemplaren
met een plaatsing van\n800 woningadvertenties.\nU komt dan op de
volgende berekening:\n\nTotaalprijs: \xe2\x82\xac 12.684,- per
uitgave, gedeeld door 800 woningadvertenties (bij 9 objecten per
pagina) is \xe2\x82\xac 30,- per woningadvertentie (bij doorberekening
aan klant). Aantal pagina\xe2\x80\x99s 89. Totaleopbrengst
\xe2\x82\xac 24.000,-\n\nU heeft dan nog 27 pagina\xe2\x80\x99s (minus
cover) over met een verdeling van 16 redactiepagina\xe2\x80\x99s (door
ons te verzorgen) en 10 advertentiepagina\xe2\x80\x99s (door ons te
verzorgen).\n\nPaginaprijs advertentiepagina \xe2\x82\xac 1.000,-
minus 50% provisie, opbrengst \xe2\x82\xac 500,- per
pagina.\n\nKostenoverzicht per editie:\n\nOpbrengsten :\n\n-
Woningadvertenties\t\t\xe2\x82\xac 24.000,-\n- Advertentie
omzet\t\t\xe2\x82\xac 5.000,-\n\t\tTotaal\t\t\xe2\x82\xac
29.000,-\n\nKosten :\n\n- Drukkosten magazine\t\t\xe2\x82\xac
12.668,-\n- Opmaak \t\t\t\xe2\x82\xac 6.902,-\n-
Redactiepagina\xe2\x80\x99s \t\t\xe2\x82\xac
6.400,-\n\t\tTotaal\t\t\xe2\x82\xac 25.970,-\n\n \nUitgaande van
bovenstaand rekenvoorbeeld, is de realisatie van het magazine volledig
kostendekkend en\nhet levert u \xe2\x82\xac 3.030,-op (op jaarbasis
\xe2\x82\xac 30.300,- ,dit kan dan o.a. worden gebruikt voor
promotie).\n\nBovenstaande prijzen zijn gebaseerd op digitale
aanlevering conform onze specificaties, \nexclusief auteurscorrecties
en BTW en gebaseerd op de huidige lonen, materialen- en
grondstofprijzen.\nOfferte is geldig tot 90 dagen na datum
uitgifte.\nOp al onze producten en diensten zijn de
leveringsvoorwaarden van de Grafische Industrie van toepassing.\n\nIk
vertrouw erop u hiermee een passende aanbieding te hebben gedaan en
zie graag uw reactie tegemoet.\n\n\n\nMet vriendelijke
groeten,\nReclame- & Drukwerkadviesbureau Muurlink BV\n\n\n\nRene
Hoekstra\nAccount manager\n'

Thanks in advance for the help. I will paste my complete python script
below that reproduces the error.

Jasper Elzinga


------------- begin script ----------------
import sys
import kinterbasdb

killermemo = ' Wijnsma RMT\n\t\tPostbus 57\n\t\t7550 AB
Hengelo\n\n\nVlaardingen, 14 februari 2005\n\n\n\nGeachte heer
Wijnsma,\n\nIk dank u voor uw aanvraag en hebben heb genoegen u onze
vrijblijvende offerte te doen toekomen voor het vervaardigen
van:\n\nObject\t: Glossy magazine (A4)\nFrequentie\t: 10x per
jaar\nOplage\t: 5.000 exemplaren \nOmvang\t: 96 / 104 / 112
pagina\xe2\x80\x99s binnenwerk in 4 pagina\xe2\x80\x99s
omslag\nFormaat\t: 210 x 297 mm per pagina, staand \nBedrukking\t:
geheel in full-colour, aflopend\nPapier\t: binnenwerk = 115 grams
houtvrij gesatineerd mc, gebaseerd op aanmaak\n\t: omslag = 250grams
houtvrij gesatineerd mc\nVeredeling\t: omslag aan buitenzijde voorzien
van glans laminaat\nAfwerking\t: garenloos gebrocheerd of genaaid
gebrocheerd in 4x gerild omslag\nVerpakking\t: handzaam in
dozen\nOpmaak\t: door ons uit te voeren aan de hand van door u aan te
leveren digitale tekstbestanden\n\t: (word-documenten), digitale
foto\xe2\x80\x99s (jpeg/tiff), digitale logo\xe2\x80\x99s (eps) en
compleet\n\t: opgemaakte digitale commerciele advertenties (hi-res
pdf/quark x-press), \n\t: een en ander uitgevoerd in een nader te
bepalen stramien/uitvoering\nLevertijd\t: in nader
overleg\nTransport\t: franco 1 adres in Nederland in 1
zending\n\t\t\t\nPrijs drukwerk\t: 5.000 exemplaren
\t\tgarenloos\tgenaaid \n\t\t: 96 + 4
pagina\xe2\x80\x99s\t\t\xe2\x82\xac 9.913,00\t\xe2\x82\xac
11.310,00\n\t\t: 104 + 4 pagina\xe2\x80\x99s\t\t\xe2\x82\xac
10.793,00\t\xe2\x82\xac 12.242,00\n\t\t: 112 + 4
pagina\xe2\x80\x99s\t\t\xe2\x82\xac 11.184,00\t\xe2\x82\xac
12.668,00\n\nPrijs opmaak\t: \xe2\x82\xac 50,00 per pagina\nDigitale
aanlevering\t: \xe2\x82\xac 9,50 per pagina voor Certified
PDF\n\nAdv.Acquisitie\t: door u aan te leveren of door ons te
verzorgen tegen 50% provisie\n\nRedactie\t: door u aan te leveren of
door ons uit te voeren tegen een tarief van \xe2\x82\xac 250,00 tot
\n\t\t: \xe2\x82\xac 400,00 per artikel/pagina\n\nPromotie\t: wij
stellen voor om de promotie van dit magazine te doen middels
commercials op\n\t\t: lokale radio en televisie al dan niet
ondersteund door een gerichte mailing aan een, \n\t\t: in overleg met
u, nader te bepalen doelgroep \n\t\t: kosten voor deze promotie zijn
na overleg met u nader te
bepalen\n\n\n\n\n\n\n\n\n\nRekenvoorbeeld:\n\nAls voorbeeld neem ik
het tarief van 112 + 4 pagina\xe2\x80\x99s, genaaid, 5.000 exemplaren
met een plaatsing van\n800 woningadvertenties.\nU komt dan op de
volgende berekening:\n\nTotaalprijs: \xe2\x82\xac 12.684,- per
uitgave, gedeeld door 800 woningadvertenties (bij 9 objecten per
pagina) is \xe2\x82\xac 30,- per woningadvertentie (bij doorberekening
aan klant). Aantal pagina\xe2\x80\x99s 89. Totaleopbrengst
\xe2\x82\xac 24.000,-\n\nU heeft dan nog 27 pagina\xe2\x80\x99s (minus
cover) over met een verdeling van 16 redactiepagina\xe2\x80\x99s (door
ons te verzorgen) en 10 advertentiepagina\xe2\x80\x99s (door ons te
verzorgen).\n\nPaginaprijs advertentiepagina \xe2\x82\xac 1.000,-
minus 50% provisie, opbrengst \xe2\x82\xac 500,- per
pagina.\n\nKostenoverzicht per editie:\n\nOpbrengsten :\n\n-
Woningadvertenties\t\t\xe2\x82\xac 24.000,-\n- Advertentie
omzet\t\t\xe2\x82\xac 5.000,-\n\t\tTotaal\t\t\xe2\x82\xac
29.000,-\n\nKosten :\n\n- Drukkosten magazine\t\t\xe2\x82\xac
12.668,-\n- Opmaak \t\t\t\xe2\x82\xac 6.902,-\n-
Redactiepagina\xe2\x80\x99s \t\t\xe2\x82\xac
6.400,-\n\t\tTotaal\t\t\xe2\x82\xac 25.970,-\n\n \nUitgaande van
bovenstaand rekenvoorbeeld, is de realisatie van het magazine volledig
kostendekkend en\nhet levert u \xe2\x82\xac 3.030,-op (op jaarbasis
\xe2\x82\xac 30.300,- ,dit kan dan o.a. worden gebruikt voor
promotie).\n\nBovenstaande prijzen zijn gebaseerd op digitale
aanlevering conform onze specificaties, \nexclusief auteurscorrecties
en BTW en gebaseerd op de huidige lonen, materialen- en
grondstofprijzen.\nOfferte is geldig tot 90 dagen na datum
uitgifte.\nOp al onze producten en diensten zijn de
leveringsvoorwaarden van de Grafische Industrie van toepassing.\n\nIk
vertrouw erop u hiermee een passende aanbieding te hebben gedaan en
zie graag uw reactie tegemoet.\n\n\n\nMet vriendelijke
groeten,\nReclame- & Drukwerkadviesbureau Muurlink BV\n\n\n\nRene
Hoekstra\nAccount manager\n'
minimalkiller = [(500011, 33, 0, 0, '', None, None, None, 5, None,
None, None, None, None, killermemo, None, None, None, None, None,
None, None, None, None, None, None)]

if __name__ == "__main__":

print "Start"

# open de database
try:
con = kinterbasdb.Connection(host="localhost",
database="c:\\database-arm.fdb", user="arm", password="arm")
cur = con.cursor()
except Exception, e:
print "cant open db:\n", e
sys.exit(-1)

# create domains
cur.execute("CREATE DOMAIN STRING AS VARCHAR(60) CHARACTER SET NONE")
cur.execute("CREATE DOMAIN TEXT AS VARCHAR(255) CHARACTER SET NONE")
cur.execute("CREATE DOMAIN MEMO AS VARCHAR(10000) CHARACTER SET NONE")
#cur.execute("CREATE DOMAIN MEMO AS BLOB SUB_TYPE TEXT CHARACTER SET
NONE")
con.commit()

# create table
query = "CREATE TABLE Correspondentie (id integer, version integer,
deleted integer, mutex integer, lockedby string, id_instantie integer,
id_persoon integer, id_functie integer, id_medewerker integer,
adresblok memo, naam text, telefoon text, fax text, email text, memo
memo, datum integer, betreft text, aanhef text, afsluiting text,
volgnummer text, id_sjabloon integer, id_document integer, kenmerk
text, uw_kenmerk text, datum_aangemaakt integer, datum_gewijzigd integer)"
cur.execute(query)
con.commit()

# add record
killding = minimalkiller
questionString = ", ".join(["?"]*len(killding[0]))
cur.executemany("INSERT INTO Correspondentie VALUES (%s)" %
questionString, killding)
con.commit()

# add temp domain
cur.execute("CREATE DOMAIN MEMOTEMP AS BLOB SUB_TYPE TEXT CHARACTER
SET NONE")
con.commit()

######
### manual select
##cur.execute("SELECT memo FROM Correspondentie")
##blata = cur.fetchall()
######

# migrate to temp column
query = "ALTER TABLE Correspondentie ADD tempmemo MEMOTEMP"
cur.execute(query); con.commit()
query = "UPDATE Correspondentie SET tempmemo=memo"
cur.execute(query); con.commit()
query = "ALTER TABLE Correspondentie DROP memo"
cur.execute(query); con.commit()
query = "ALTER TABLE Correspondentie ADD tempadresblok MEMOTEMP"
cur.execute(query); con.commit()
query = "UPDATE Correspondentie SET tempadresblok=adresblok"
cur.execute(query); con.commit()
query = "ALTER TABLE Correspondentie DROP adresblok"
cur.execute(query); con.commit()

# convert domain MEMO
cur.execute("DROP DOMAIN MEMO")
cur.execute("CREATE DOMAIN MEMO AS BLOB SUB_TYPE TEXT CHARACTER SET
NONE")
con.commit()

# migrate back from temp column
query = "ALTER TABLE Correspondentie ADD memo MEMO"
cur.execute(query); con.commit()
query = "UPDATE Correspondentie SET memo=tempmemo"
cur.execute(query); con.commit()
query = "ALTER TABLE Correspondentie DROP tempmemo"
cur.execute(query); con.commit()
query = "ALTER TABLE Correspondentie ADD adresblok MEMO"
cur.execute(query); con.commit()
query = "UPDATE Correspondentie SET adresblok=tempadresblok"
cur.execute(query); con.commit()
query = "ALTER TABLE Correspondentie DROP tempadresblok"
cur.execute(query); con.commit()

######
### manual update
##cur.executemany("UPDATE Correspondentie SET memo=?", blata)
##con.commit()
######

# drop temp domain
cur.execute("DROP DOMAIN MEMOTEMP")
con.commit()

## print record(s)
#print
#cur.execute("SELECT * from Correspondentie")
#print "data", cur.fetchall()
#print

# try to drop te table...
print "DIE!!"
query = "DROP TABLE Correspondentie"
print query
cur.execute(query)
print "query executed"
con.commit()
print "committed"

print
print "Done!"
------------- end script ----------------