31/01/2010

"Decimal byte array constructor requires an array of length four containing valid decimal bytes"

Home

"Decimal byte array constructor requires an array of length four containing valid decimal bytes"

Z takim błędem spotkałem się ostatnio pisząc kod komunikujący się z bazą danych. Niestety ale błąd ten miał również dwie utrudniające jego poprawienie właściwości. Po pierwsze pojawiał się na kilku komputerach ale nie na moim. No cóż syndrom "a u mnie działa" zdarza się każdemu. Po drugie kod w jakim występował zdawał się wyglądać całkowicie niewinnie:
DataSet ds = New DataSet

OleDbDataAdapter adapter = New OleDbDataAdapter
adapter.SelectCommand = New OleDbCommand(Command, Connection)

adapter.Fill(ds)
Dokładniej mówiąc wyjątek pojawiał sie przy wywołaniu metody Fill. Kiedy zapytałem wyszukiwarkę o treść komunikatu znalazłem kilkanaście forów z pytaniami dotyczącymi tego błędy w kontekście komunikacji z różnymi bazami danych (ja używam bazy danych Informix). Niestety prawie wszystkie zadane pytania zostały bez odpowiedzi. Znalazłem jednak wypowiedź sugerującą, że błąd pojawia się jeśli w zapytaniu użyto funkcji agregujących.

Zapytanie, którego ja użyłem zawierało całkiem sporo przykładów użycia funkcji agregujących, postanowiłem więc usunąć je z zapytania i zobaczyć co się stanie. W wyniku modyfikacji zapytania wyjątek nie pojawił się. Miałem więc już jakąś wskazówkę co robić dalej. W następnym kroku dodawałem do zapytania kolejne odwołania do funkcji agregujących żeby zobaczyć, które dokładnie spowoduje błąd.

Po kilku próbach znalazłem kłopotliwy fragment zapytania. Wyglądał on tak:
SELECT ..., SUM(Col1) - Sum(Col2), ... 
W tym momencie przypomniałem sobie pewną rzecz i już wiedziałem jak rozwiązać problem. Tak jak napisałem wcześniej błąd nie pojawiał się na komputerze, na którym pracowałem. Dane, które pobrałem z bazy danych mogłem, więc wyświetlić na kontrolce gridowej. Kiedy zrobiłem to po raz pierwszy zauważyłem, że w niektórych kolumnach liczby prezentowane są z bardzo dużą precyzję pomimo, że na poziomie bazy danych użyto typu DECIMAL o precyzji 2. Problem rozwiązałem wymuszając po prostu odpowiednie formatowanie. Teraz jednak okazało się, że kolumny o "dziwnym" formatowaniu na mojej maszynie pokrywały się z przykładami użycia funckji, które powodowały błąd na innych stacjach.

Pierwszy wniosek jest taki, że wynik operacji arytmetycznych na rezultatach działania funkcji agregujących może mieć wyższą precyzję niż by to wynikało z typu kolumn. W przypadku niektórych działań arytmetycznych ma to oczywiście sens, chociaż nie w przypadku odejmowania czy dodawania. Ale mniejsza o tym. Istotne jest to, że z powodu zwiększonej precyzji nie jest potem możliwe skonstruowanie wartości typu decimal i generowany jest wyjątek. Rozwiązanie jest proste. Trzeba zaokrąglić wynik:
SELECT ..., ROUND(SUM(COl1) - Sum(Col2), 2), ... 
Z tego co się dowiedziałem pomóc może również użycie nowszych sterowników OLEDB. Z drugiej strony na moim komputerze zainstalowana jest taka sama wersja sterowników jak na innych. Różnica jest taka, że ja używam Windows 7 ale trudno powiedzieć czy to ma jakiś wpływ. W każdym razie pytanie czemu błąd nie pojawia się na wszystkich stacjach pozostaje otwarte.

06/01/2010

Uruchamianie aplikacji na 64 bitach

Home

Pierwszy wpis w nowym roku 2010 będzie dotyczył zagadnienia uruchamiania aplikacji .Net'owych na maszynach 64 bitowy. W większości przypadków nie ma z tym żadnego problemu. W końcu IL jest przenośny. Problemy zaczynają się kiedy chcemy wykorzystać w swojej aplikacji biblioteki 32 bitowe. Niestety ale nie jest możliwe aby proces 64 bitowy używał bibliotek 32 bitowych i na odwrót. Przeważnie nie mamy również możliwości przekompilowania biblioteki, z której korzystamy. Ja spotkałem się z tym problem uruchamiając aplikację, która do połączenia z bazą danych korzystała ze sterownika ODBC. W czasie jej uruchomienia pojawiał się komunikat:

Dostawca 'Ifxoledbc.2' nie jest zarejestrowany na lokalnym komputerze.

Komunikat mnie zdziwił ponieważ byłem pewny, że dostawca jest zarejestrowany. Przypomniałem sobie jednak, że jest to sterownik 32 bitowy. Jak sobie poradziłem?

Ogólnie są dwa rozwiązania tego problemu. Po pierwsze można w właściwościach projektu ustawić opcję Target CPU na X86. Domyślna wartość to Any CPU. Jeśli z jakichś powodów nie możemy zrekompilować aplikacji możemy skorzystać z programu corflags. Jest on instalowany razem z Visual Studio i pozwala przełączyć aplikację w 32 bitowy tryb pracy np.:

corflags /32bit+ aplikacja

W razie potrzeby ponownego przełączenia na 64 bitowy tryb pracy używamy następującej składni:

corflags /32bit- aplikacja