Błąd przy zapisie do bazy

Problemy związane z tworzeniem i zarządzaniem programami bazo-danowymi.
Regulamin działu


Zadając pytania dotyczące baz danych należy podawać szczegółowe informacje o bazie danych nad którą się pracuje, czyli:

  • Rodzaj serwera bazodanowego: MySql, MSSQL, Oracle itp.
  • Wersja bazy danych
  • Technologia bazodanowa używana w programie: ADO, DbExpress, InterBase
  • Komponenty użyte do zestawienia połączenia: ADOConnection, SqlConnection
  • Sposób zestawienia komponentów bazodanowych np. DataSet - DataSource - DbGrid lub DataSet - DataSetProvider - ClientDataSet - DataSource - DbGrid
  • Jeżeli używane były biblioteki innych firm niż Borland, CodeGeer i Embarcadero proszę podać ich nazwy, numer wersji i adres źródła.

Błąd przy zapisie do bazy

Nowy postprzez mentalmesh » piątek, 19 lutego 2010, 16:04

Witam,
Mam problem z baza danych InterBase 2009. Program składa w zmiennej AnsiString zapytanie SQL z fragmentów i finalnie ładuje to do IBQuery->SQL->Text.
Jednym z parametrów jest kod HTML (konkretnie tresc maila w formacie HTML), przy wstawianiu "zwykłego" tekstu nie miałem problemów ale przy html kompilator wypluwa błąd:

Project XXXX.exe raised exception class EIBClientError with message 'XSQLDA index out of range'.


kod jest wstawiany do komórki VARCHAR(5000) - treść maila raczej nie jest dłuższa, oszacowałem ją na jakieś 2000 znaków. Początkowo błędy generowały znaki ' (apostrof), które zmieniały sens zapytania, ale teraz przed wstawieniem każdy znak ' z treści jest zamieniany na " (cudzysłów) a ; na \; więc to też nie powinno być przyczyną błędu.
Wiecie może co może być przyczyną tego błędu i jak temu zaradzić?
Z góry dziękuję za pomoc.
Pozdrawiam
Avatar użytkownika
mentalmesh
Bladawiec
Bladawiec
 
Posty: 26
Dołączył(a): piątek, 5 czerwca 2009, 04:44
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP Pro SP3
Windows 7 Prof x64
Kompilator: C++ Builder 2009, InterBase 2009
Gadu Gadu: 0
    Windows XPFirefox

Re: Błąd przy zapisie do bazy

Nowy postprzez Cyfrowy Baron » piątek, 19 lutego 2010, 18:50

' z treści jest zamieniany na " (cudzysłów)


Cudzysłowy też będą generować błędy, np. taki kod html:

Kod: Zaznacz cały
<font color="#505050" face="Verdana" STYLE="font-variant: small-caps; font-size:9pt">


zawiera wewnątrz cudzysłowy i taki zapis będzie powodować błędy ale tylko wtedy gdy taki kod zostanie zawarty w kodzie programu, dlatego każdy cudzysłów powinien być poprzedzony ukośnikiem:

Kod: Zaznacz cały
<font color=\"#505050\" face=\"Verdana\" STYLE=\"font-variant: small-caps; font-size:9pt\">


Jeżeli jednak kod HTML jest wprowadzany w programie lub wczytywany z pliku, to nie ma to znaczenia.



Napisałeś, że zwykły tekst nie generuje błędów, więc jeżeli zawrzesz w zwykłym tekście apostrof to czy on generuje błąd czy nie?
Kod HTML to też zwykły tekst.



a ; na \; więc to też nie powinno być przyczyną błędu.


Jak rozumiem zamieniłeś średnik na średnik z ukośnikiem, czyli: ; = \;
jeżeli tak to tylko dodałeś ukośnik, średnik pozostał.
Nie jestem pewien, ale średnik chyba nie powinien generować błędów.
Być może dwukropki?!

Za ten post autor Cyfrowy Baron otrzymał podziękowanie od:
mentalmesh
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4719
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Błąd przy zapisie do bazy

Nowy postprzez mentalmesh » sobota, 20 lutego 2010, 01:14

"zwykły tekst" rozumiem przez tekst bez znaków specjalnych ktore "coś" znaczą w kodzie sql - średnik poprzedziłem ukośnikiem gdyż sam średnik jest zakończeniem polecenia sql. Sprawdzałem z poziomu Interactive SQL, że znaki specjalne poprzedzone \ nie generują błędów - apostrof jest wyjątkiem dlatego zamieniłem go na " który można swobodnie wstawić w sql jako tekst. Apostrof nawet poprzedzony ukośnikiem będzie generował błąd.
Dla przykładu:
Kod: Zaznacz cały

AnsiString tresc = "cos ; cos";
AnsiString zm_sql = "INSERT INTO TABELA VALUES(1,'+tresc+');";
IBQuery1->Active=false;
IBQuery1->SQL->Text=zm_sql;
IBQuery1->Active=true;

Uprzedzam ewentualne pytanie - w wersji 2009 borlanda taka sekwencja daje ten sam efekt co wywołanie ExecSQL (czy jakos tak... z tej drugiej metody nie korzystam wiec nie pamietam dokladnie jak sie pisze).
Kod który wstawiłem wypluje błąd ponieważ średnik spowoduje, że finalne zapytanie będzie miało forme:
Kod: Zaznacz cały
INSERT INTO TABELA VALUES (1,'cos ; cos');
co jest błędem.
Natomiast jeśli zmodyfikujemy kod do postaci:
Kod: Zaznacz cały

AnsiString tresc = "cos \; cos";
AnsiString zm_sql = "INSERT INTO TABELA VALUES(1,'+tresc+');";
IBQuery1->Active=false;
IBQuery1->SQL->Text=zm_sql;
IBQuery1->Active=true;

finalne zapytanie SQL będzie miało postać:
Kod: Zaznacz cały
INSERT INTO TABELA VALUES (1,'cos \; cos');

a taki kod w interacive SQL jest wykonywany prawidłowo - analogicznie cudzysłów.
Jeżeli zmienna tresc="cos ; cos" baza zwróci błąd ale "cos \; cos" już nie.
Mam to sprawdzone gdyż takie ciągi znaków wstawiałem do bazy i nie generowały błędów. Cudzysłów zamiast średnika wchodzi bez problemu ( z tą różnicą, że w kodzie C++ musi być poprzedzony \).
Nie jestem pewien czy jakieś inne znaki nie powodują błędów np. <, # itd ale apostrof, średnik i cudzysłów sprawdzałem i używałem z ukośnikiem i było ok.

Informacja błędu sugeruje, że index XSQLDA jest poza zakresem (jeśli dobrze przetłumaczyłem) ale nie mogę się doszukać informacji co to za indeks i za co on jest odpowiedzialny - w sieci widziałem pytania o ten indeks i o ten sam komunikat niestety na pytaniach się kończyło :(
Avatar użytkownika
mentalmesh
Bladawiec
Bladawiec
 
Posty: 26
Dołączył(a): piątek, 5 czerwca 2009, 04:44
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP Pro SP3
Windows 7 Prof x64
Kompilator: C++ Builder 2009, InterBase 2009
Gadu Gadu: 0
    Windows XPFirefox

Re: Błąd przy zapisie do bazy

Nowy postprzez Cyfrowy Baron » sobota, 20 lutego 2010, 10:25

W sieci trudno coś znaleźć na temat tego błędu, ale na jakimś rosyjskim forum natknąłem się na info, że dwukropek też wywołuje błąd.
Na innym forum znalazłem info, że nie można używać znaku kratki #.

Tutaj jest trochę o InterBase: http://www.dbf.pl/faq/faq_pcbd.html#interbase

Ten PDF po polsku też może być przydatny: http://kni.kul.lublin.pl/~andy/ref/other/interbase.pdf




Znalazłem coś takiego na stronie: http://acssql.wpk.p.lodz.pl/65rozdz1.htm
może się przyda:

Typy znakowe

Typy znakowe umożliwiają przechowywanie danych o szerszej niż numeryczne różnorodności symboli. Są przystosowane do przechowywania liter, symboli numerycznych i specjalnych znaków takich jak ? czy >. Wprowadza się je do tabel używają pojedynczego bądź podwójnego nawiasu.
char

Jest pierwszym typem znakowym. Kiedy dane przechowywane są w typie char, każdy przechowywany symbol lub znak zajmuje 1 bajt. Liczba podana w nawiasach zwykłych określa rozmiar każdego przechowywanego zbioru znaków. Na przykład, jeśli zdefiniowana zostanie tabela o kolumnie z typem char(15) , każda wartość kolumny ma rozmiar 15 bajtów i może przechować 15 znaków. Jeśli wprowadzony łańcuch będzie krótszy niż 15 znaków SQL doda puste znali za ostatnim wprowadzonym.

Można określić char(n) tak by zawierał nawet do 255 znaków. Należy jednak pamiętać że wartości wszystkich elementów takiej kolumny zawierają wprowadzoną liczbę znaków bowiem SQL automatycznie wypełnia wolne w łańcuchach miejsca.
vorchar

Można użyć tego typu do składowania danych o różnej długości aż do 255. W przeciwieństwie do typu char, użyta przestrzeń przechowująca zmienia się odpowiednio do liczby znaków przechowywanych we wszystkich wartościach rzędów danej kolumny.
datetime i smalldatetime

Są to typy przechowujące kombinację daty i czasu. Okaże się o wiele wygodniejsze używanie do przechowywania dat i czasu w jednym z tych typów niż w typie takim jak char czy vorchar. Jeżeli złożysz dane w jednym z takich typów, możesz je łatwo wyświetlić ponieważ SQL automatycznie formatuje je do znanej formy. Można również używać specjalizowanych funkcji manipulujących datą i czasem.

Jeżeli przechowujesz datę i czas w typie char lub vorchar (lub też jeśli składujesz takie wartości w typach numerycznych), data i czas nie będą automatycznie formatowane do postaci w jakiej są konwencjonalnie wyświetlane.
datetime

Pierwszy typ daty i czasu który może być użyty do definiowania struktur takich jak tabele kolumn. W tym typie można przechowywać daty i czasy od 1/1/1753 AD to 12/31/9999 AD.

Typ zajmuje 8 bajtów. SQL Serwer używa pierwszych 4 bajtów do zapamiętania liczby dni przed lub po datą bazową 01/01/1900. Wartości które są przechowywane jako ujemne reprezentują daty przed datą bazową, dodatnie daty po dniu bazowym. Czas jest przechowywany w następnych 4 bajtach jako liczba milisekund po północy.
smalldatetime

Jest drugim typem daty i czasu który może być wykorzystany przy definiowaniu struktur przechowujących dane takich jak kolumny tabel. W powyższym typie można przechować daty i czas od 1/1/1900 AD do 6/6/2079 AD.

Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4719
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Błąd przy zapisie do bazy

Nowy postprzez mentalmesh » sobota, 20 lutego 2010, 20:40

Dzięki, zapoznam się z tymi plikami może uda się coś znaleźć.
Sprawdziłem wszystkie znaki w Interactive SQL - "niestety" wszystko poza apostrofem wchodzi bez problemów.
Kod: Zaznacz cały
INSERT INTO TABELA VALUES (1,':[]{}\/.,;)(*&^%$#@!~`" :cos - + ={}<>?/|');

Nawet nie trzeba dodawać ukośników do tych znaków. Apostrof natomiast nawet jeśli będzie poprzedzony \ i tak będzie generował błąd.
Macie jeszcze jakieś pomysły?
Avatar użytkownika
mentalmesh
Bladawiec
Bladawiec
 
Posty: 26
Dołączył(a): piątek, 5 czerwca 2009, 04:44
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP Pro SP3
Windows 7 Prof x64
Kompilator: C++ Builder 2009, InterBase 2009
Gadu Gadu: 0
    Windows XPFirefox

Re: Błąd przy zapisie do bazy

Nowy postprzez mentalmesh » sobota, 20 lutego 2010, 22:49

Mam nowe informacje związane z problemem:
1. tak jak pisałem znaki wchodzą wszystkie poza apostrofem
2. z poziomu Interactive SQL każdy e-mail wpisał się do bazy - załadowałem do memo treść maila a nastepnie copy/past do Interactive SQL.
3. jeżeli w programie podam losowy ciąg znaków - nawet podobnej lub większej długości to też się dodaje prawidłowo.
4. przekopiowałem całe zapytania SQL które składa program i wkleiłem do Interactive SQL i też się wykonały - każdy z 7 e-mail wpisał się prawidłowo.
Z punktów 2 - 4 wynika, że na pewno nie jest to błąd bazy InterBase.
W związku z powyższym nie mam już pomysłów co jeszcze mógłbym sprawdzić. Na pewno błąd jest gdzieś na etapie "kompilatora" a nie samej bazy, kod programu raczej powinien być dobry (SQL się wykonywał więc jest OK, a inne ciągi również wchodzą bez problemów). Jednocześnie wykluczyłem opcję, że samo zapytanie do bazy jest zbyt długie.
Jest możliwe, że jeśli pobieram treść przez wykonanie kodu IdMessage->Body->Text i przypisuje do zmiennej AnsiString to nie zgadzają się typy albo następuje jakaś dziwna "konwersja" danych?

Załączam kod, który pobiera treść wiadomości:
Kod: Zaznacz cały
AnsiString Tresc="";
if(IdMWiadomosc->ContentType=="multipart/alternative")
            {
              for(int i=0;i<IdMWiadomosc->MessageParts->Count;i++)
              {
               if(IdMWiadomosc->MessageParts->Items[i]->DisplayName=="TIdText")
               {
                TIdText *IdText = (TIdText*)IdMWiadomosc->MessageParts->Items[i];
                Tresc = Tresc + Trim(IdText->Body->Text);
               }
              }
             ShowMessage(Tresc);
            }
            else if(IdMWiadomosc->ContentType=="text/plain")
            {
              Tresc=Trim(IdMWiadomosc->Body->Text);
            }
            else if(IdMWiadomosc->ContentType=="text/html")
            {
              Tresc=Trim(IdMWiadomosc->Body->Text);
            }
Avatar użytkownika
mentalmesh
Bladawiec
Bladawiec
 
Posty: 26
Dołączył(a): piątek, 5 czerwca 2009, 04:44
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP Pro SP3
Windows 7 Prof x64
Kompilator: C++ Builder 2009, InterBase 2009
Gadu Gadu: 0
    Windows XPFirefox

Re: Błąd przy zapisie do bazy

Nowy postprzez Cyfrowy Baron » sobota, 20 lutego 2010, 23:06

Jest możliwe, że jeśli pobieram treść przez wykonanie kodu IdMessage->Body->Text i przypisuje do zmiennej AnsiString to nie zgadzają się typy albo następuje jakaś dziwna "konwersja" danych?


Gdybyś uzupełnił profil było by wiadomo jakiego kompilatora używasz, a tak to można tylko zgadywać.

Jeżeli korzystasz ze środowiska C++Builder 2009 lub 2010 to przepisując IdMessage->Body->Text do typu AnsiString dokonujesz konwersji z UnicodeString na AnsiString, gdyż Body->Text w tych środowiskach jest właśnie typu UnicodeString.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4719
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Błąd przy zapisie do bazy

Nowy postprzez mentalmesh » niedziela, 21 lutego 2010, 01:08

Sorry, zapomniałem dopisać - korzystam z wersji C++Builder 2009 i InterBase 2009.
A jest możliwe, że konwersja między tymi dwoma formatami powoduje błąd? W sumie oba typy to typy znakowe więc nie powinny stwarzać problemów...
Avatar użytkownika
mentalmesh
Bladawiec
Bladawiec
 
Posty: 26
Dołączył(a): piątek, 5 czerwca 2009, 04:44
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP Pro SP3
Windows 7 Prof x64
Kompilator: C++ Builder 2009, InterBase 2009
Gadu Gadu: 0
    Windows XPFirefox

Re: Błąd przy zapisie do bazy

Nowy postprzez Cyfrowy Baron » niedziela, 21 lutego 2010, 12:09

Nie jest to błędem, ale UnicodeString obsługuje więcej znaków niż AnsiStirng.

Zamiast deklarować typ AniString deklaruj UnicodeString, czyli po prostu String:

Kod: Zaznacz cały
String Tresc = "";

if(IdMWiadomosc->ContentType == "multipart/alternative")
{
  for(int i = 0; i < IdMWiadomosc->MessageParts->Count; i++)
  {
    if(IdMWiadomosc->MessageParts->Items[i]->DisplayName == "TIdText")
    {
      TIdText *IdText = (TIdText*)IdMWiadomosc->MessageParts->Items[i];
      Tresc = Tresc + Trim(IdText->Body->Text);
    }
  }
  ShowMessage(Tresc);
}
else if(IdMWiadomosc->ContentType == "text/plain")
{
  Tresc = Trim(IdMWiadomosc->Body->Text);
}
else if(IdMWiadomosc->ContentType == "text/html")
{
  Tresc = Trim(IdMWiadomosc->Body->Text);
}


W C++Builder 2009 i 2010 inaczej niż we wcześniejszych wersjach deklaracja String jest traktowana jako typ UnicodeString, a nie AnsiString.



Pisząc kod nie twórz długich ciągów znaków, gdyż trudno analizować taki kod. Nie bój się używać spacji:

nie tak:
Kod: Zaznacz cały
if(IdMWiadomosc->ContentType=="multipart/alternative")


lecz tak:
Kod: Zaznacz cały
if(IdMWiadomosc->ContentType == "multipart/alternative")


lub nawet tak:
Kod: Zaznacz cały
if( IdMWiadomosc->ContentType == "multipart/alternative" )


Jak widzisz tak jest czytelniej, widać co jest czym.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4719
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Błąd przy zapisie do bazy

Nowy postprzez mentalmesh » niedziela, 21 lutego 2010, 16:24

Niestety nawet po zmianie wszystkich zmiennych na UnicodeString pojawia się błąd XSQLDA index out of range.
Avatar użytkownika
mentalmesh
Bladawiec
Bladawiec
 
Posty: 26
Dołączył(a): piątek, 5 czerwca 2009, 04:44
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP Pro SP3
Windows 7 Prof x64
Kompilator: C++ Builder 2009, InterBase 2009
Gadu Gadu: 0
    Windows XPFirefox

Re: Błąd przy zapisie do bazy

Nowy postprzez mentalmesh » niedziela, 21 lutego 2010, 17:42

Ok, mam odpowiedź wreszcie - jednak błąd generował " ale tylko jeśli ciąg znaków jest wprowadzany w C++Builder do IBQuery, jeśli wpisze się w Interactive SQL:
INSERT INTO TABELA VALUES (1,' " '); to wchodzi bez problemów.
Dzięki za pomoc :)
Pozdrawiam,
MentalMesh
Avatar użytkownika
mentalmesh
Bladawiec
Bladawiec
 
Posty: 26
Dołączył(a): piątek, 5 czerwca 2009, 04:44
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP Pro SP3
Windows 7 Prof x64
Kompilator: C++ Builder 2009, InterBase 2009
Gadu Gadu: 0
    Windows XPFirefox

Re: Błąd przy zapisie do bazy

Nowy postprzez Cyfrowy Baron » niedziela, 21 lutego 2010, 20:34

W tym poście viewtopic.php?p=5598#p5584 pisałem Tobie o tym, ale Ty twierdziłeś, że można tego swobodnie używać.
Czasami warto sprawdzić.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4719
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Błąd przy zapisie do bazy

Nowy postprzez mentalmesh » niedziela, 21 lutego 2010, 21:35

Tak, owszem... problem w tym, że baza to przyjmuje, błąd powstaje tylko i wyłącznie jeśli string przechodzi przez IBQuery. Początkowo testowałem na samej bazie. Kod C++ też łyka \" ale do czasu wykonania w IBQuery - dziwne trochę - założyłem, że jeśli baza przyjmie znaki to kompilator tym bardziej dlatego sprawdziłem w Interactive SQL zamiast w C++Builder.
Dzięki raz jeszcze za pomoc :)
Pozdrawiam
Avatar użytkownika
mentalmesh
Bladawiec
Bladawiec
 
Posty: 26
Dołączył(a): piątek, 5 czerwca 2009, 04:44
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP Pro SP3
Windows 7 Prof x64
Kompilator: C++ Builder 2009, InterBase 2009
Gadu Gadu: 0
    Windows XPFirefox


  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Bazy danych

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 1 gość

cron