MsSQL not work with national letter in WebApp

The issue will be with encodings. If your columns are defined without the ‘n’ or “national” prefix e.g. nVarChar then the encoding of the string is Windows ANSI and you’ll need to define the encoding and convert it to UTF8. This also applies with the ‘n’ prefix you’ll need to define the encoding that was used to insert the data and then convert it to UTF8.

I have shared an extension method at https://forum.xojo.com/t/mssqlstringvalue-extension-method/68251 which will help with the Windows ANSI columns.

i used the code:

row.ColumnAt(1).StringValue.DefineEncoding(Encodings.WindowsANSI).ConvertEncoding(Encodings.UTF8)

and there are no errors. the letters in the database are ok but in the WebListBox they are invalid Ł = £, Ą = ¥…

What happens if you use:

row.ColumnAt(1).StringValue.DefineEncoding(Encodings.UTF8)

the program hangs :frowning:

Can you write it any better?

Public Function FromDB(inputText As String) As String
  
  inputText = inputText.DefineEncoding(Encodings.WindowsANSI).ConvertEncoding(Encodings.UTF8)
  
  Var anArray() As String
  anArray = inputText.SplitBytes("")
  
  For i As Integer = 0 To anArray.LastIndex Step 2
    if anArray(i).Asc = 194 And anArray(i+1).Asc = 165 Then
      inputText = inputText.Left(i/2) + "Ą" + inputText.Right(inputText.Length - (i/2) - 1)
    End If
    if anArray(i).Asc = 194 And anArray(i+1).Asc = 185 Then
      inputText = inputText.Left(i/2) + "ą" + inputText.Right(inputText.Length - (i/2) - 1)
    End If
    
    if anArray(i).Asc = 195 And anArray(i+1).Asc = 134 Then
      inputText = inputText.Left(i/2) + "Ć" + inputText.Right(inputText.Length - (i/2) - 1)
    End If
    if anArray(i).Asc = 195 And anArray(i+1).Asc = 166 Then
      inputText = inputText.Left(i/2) + "ć" + inputText.Right(inputText.Length - (i/2) - 1)
    End If
    
    if anArray(i).Asc = 195 And anArray(i+1).Asc = 138 Then
      inputText = inputText.Left(i/2) + "Ę" + inputText.Right(inputText.Length - (i/2) - 1)
    End 
    If anArray(i).Asc = 195 And anArray(i+1).Asc = 170 Then
      inputText = inputText.Left(i/2) + "ę" + inputText.Right(inputText.Length - (i/2) - 1)
    End If
    
    if anArray(i).Asc = 194 And anArray(i+1).Asc = 163 Then
      inputText = inputText.Left(i/2) + "Ł" + inputText.Right(inputText.Length - (i/2) - 1)
    End 
    If anArray(i).Asc = 194 And anArray(i+1).Asc = 179 Then
      inputText = inputText.Left(i/2) + "ł" + inputText.Right(inputText.Length - (i/2) - 1)
    End If
    
    if anArray(i).Asc = 195 And anArray(i+1).Asc = 145 Then
      inputText = inputText.Left(i/2) + "Ń" + inputText.Right(inputText.Length - (i/2) - 1)
    End 
    If anArray(i).Asc = 195 And anArray(i+1).Asc = 177 Then
      inputText = inputText.Left(i/2) + "ń" + inputText.Right(inputText.Length - (i/2) - 1)
    End If
    
    if anArray(i).Asc = 195 And anArray(i+1).Asc = 147 Then
      inputText = inputText.Left(i/2) + "Ó" + inputText.Right(inputText.Length - (i/2) - 1)
    End 
    If anArray(i).Asc = 195 And anArray(i+1).Asc = 179 Then
      inputText = inputText.Left(i/2) + "ó" + inputText.Right(inputText.Length - (i/2) - 1)
    End If
    
    if anArray(i).Asc = 197 And anArray(i+1).Asc = 146 Then
      inputText = inputText.Left(i/2) + "Ś" + inputText.Right(inputText.Length - (i/2) - 1)
    End 
    If anArray(i).Asc = 197 And anArray(i+1).Asc = 147 Then
      inputText = inputText.Left(i/2) + "ś" + inputText.Right(inputText.Length - (i/2) - 1)
    End If
    
    if anArray(i).Asc = 194 And anArray(i+1).Asc = 143 Then
      inputText = inputText.Left(i/2) + "Ź" + inputText.Right(inputText.Length - (i/2) - 1)
    End 
    If anArray(i).Asc = 197 And anArray(i+1).Asc = 184 Then
      inputText = inputText.Left(i/2) + "ź" + inputText.Right(inputText.Length - (i/2) - 1)
    End If
    
    if anArray(i).Asc = 194 And anArray(i+1).Asc = 175 Then
      inputText = inputText.Left(i/2) + "Ż" + inputText.Right(inputText.Length - (i/2) - 1)
    End 
    If anArray(i).Asc = 194 And anArray(i+1).Asc = 191 Then
      inputText = inputText.Left(i/2) + "ż" + inputText.Right(inputText.Length - (i/2) - 1)
    End If
  Next
  
  Return inputText
End Function

An app never hangs. It’s just busy. You didn’t say on which OS you are working. On macOS you can get a rough overview on the app with the Activity Viewer. You can always break into the debugger to see where the app got stuck.

You don’t need to fiddle around with single characters except you got mojibake.

My operating system is Windows 10 Home 64-bit.
There is no message in the debugger.
My program is very simple. Everything works fine, only Polish characters cause the application to stop working.

I can upload an app

Where it says stack go to the other thread or click on the debugger triangle to continue. I’ve seen it a couple of times that the app drops into the debugger when it shouldn’t.

When I press continue the application works but the data is not displayed in the WebListBox
the error is in line

ListBox1.AddRow(row.ColumnAt(0).StringValue, row.ColumnAt(1).StringValue, _
row.ColumnAt(2).StringValue, row.ColumnAt(3).StringValue, row.ColumnAt(4).StringValue)

if there are Polish characters in column 4, the line does not execute correctly

this code with my “FromDB” function works fine

If data <> Nil Then
  For Each row As DatabaseRow In data
    Var s4 As String = App.FromDB(row.ColumnAt(4).StringValue)
    
    //ListBox1.AddRow(row.ColumnAt(0).StringValue, row.ColumnAt(1).StringValue, _
    //row.ColumnAt(2).StringValue, row.ColumnAt(3).StringValue, row.ColumnAt(4).StringValue)
    ListBox1.AddRow(row.ColumnAt(0).StringValue, row.ColumnAt(1).StringValue, _
    row.ColumnAt(2).StringValue, row.ColumnAt(3).StringValue, s4)
  Next
  
  data.Close
End If

from the database, the data is read correctly (attachment), but there are some hidden characters and the s4 variable cannot be assigned to Me.TextFieldOpis.Text.
When I “manually” change the data to the letters “ĄąĆćĘę…” everything works

On the end of that line in the debugger is a magnifying glass. If you click that, what Encoding is shown? In order to assign it to the window you need it to be UTF8.

That means that s4 does not have the correct encoding.

Yes, indeed. Encoding = Nil :open_mouth:

You need to determine the actual encoding and use DefineEncoding to set it. That may well be enough. If that doesn’t resolve your problem, then after you have used DefineEncoding to set the original encoding, use ConvertEncoding to change it to UTF8.

When:

s4 = row.ColumnAt(4).StringValue.DefineEncoding(Encodings.UTF8)

View As Windows-1250

Then you need to do the following:

s4 = row.ColumnAt(4).StringValue.DefineEncoding(Encodings.WindowLatin2).ConvertEncoding(Encodings.UTF8)

You need to tell Xojo what the original encoding is (using define encoding) and then convert it for UTF8 that is used internally by Xojo.

Windows-1250 is also known as WindowsLatin2

1 Like

Works

s4 = row.ColumnAt(4).StringValue.DefineEncoding(Encodings.WindowsLatin2).ConvertEncoding(Encodings.UTF8)

EDIT: thank you Ian Kennedy, identical answer. I got there by trial and error :)))

I create a table like below:

mDb.Host = host // Or use the instance name, such as ".\SQLEXPRESS"
mDb.UserName = userName
mDb.Password = password
mDb.DatabaseName = databasename

Try
  mDb.Connect()
  mDb.SQLExecute("SET NAMES utf8;")
Catch err As DatabaseException
  mIsConnected = False
  //ConnectStatusLabel.Text = "Error connecting to MS SQL Server: " + err.Message
  Return
End Try

mIsConnected = True

// Czy jest tabela //
Var sql As String = "SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'rg_kasa';"
Var data As RowSet

try
  data = mDB.SelectSQL(sql)
Catch err as DatabaseException
  Print("DB Error: " + err.Message)
  Return
End Try

If data <> Nil Then
  var t as String = ""
  For Each row As DatabaseRow In data
    t = row.ColumnAt(0).StringValue
  Next
  Print("<> Nil")
  //CreateTableStatusLabel.Text = "<> Nil"
  data.Close
  if t = "" then
    Var sqlCreate As String = "CREATE TABLE rg_kasa (" 
    sqlCreate = sqlCreate + "id int NOT NULL IDENTITY(1,1) PRIMARY KEY,"
    sqlCreate = sqlCreate + "id_users int,"
    sqlCreate = sqlCreate + "data char(10),"
    sqlCreate = sqlCreate + "wartosc decimal(14,2),"
    sqlCreate = sqlCreate + "saldo decimal(14,2),"
    sqlCreate = sqlCreate + "opis VARCHAR(200)"
    sqlCreate = sqlCreate + ");"
    Try
      mDB.ExecuteSQL(sqlCreate)
    Catch err As DatabaseException
      //CreateTableStatusLabel.Text = "DB Error: " + err.Message
      Return
    End Try
  End If

can i improve something here?

This does not cause the database to store data in UTF8. Only that the column and table names are defined using UTF8 encoding. If you want your data stored in UTF8 you need to define that on the tables, or the database level.

If you are importing data into the database from another source then it will have an encoding, which you need either to respect or convert before storing it. If the database already contains data it would also have to be converted if you want to change the database.

If you already have a working database, that is used by another application or interface, then you should stick to that. In the Xojo app use the DefineEncoding and CovertEncoding to use that data in Xojo. You would also need to do the opposite if storing data back into the database from Xojo.

// Read from the database
s4 = row.ColumnAt(4).StringValue.DefineEncoding(Encodings.WindowsLatin2).ConvertEncoding(Encodings.UTF8)

// Alter the data in what ever way you want.

// Save data back into the database
row.ColumnAt(4).StringValue = s4.ConvertEncoding(Encodings.WindowsLatin2)
1 Like

That tells the database, “I promise to store data that is UTF8”. The database will take you at your word. It will not convert any data to UTF8 automatically. You can store any encoding in the column and the database doesn’t care. When you pull data from the table, it’s up to you to know the original encoding so you can handle it correctly.

I’m sorry, but it doesn’t do that at all. It tells the database that the SQL command is using UTF8 character set. Not that the data in the columns are stored in UTF8.

To use UTF8 correctly in a database you need to set the “charset” and “collation” to UTF8. Otherwise your data isn’t expected to be in UTF8 and will not be sorted correctly by an index or order by statement.

The best way of dealing with this is to set the database default to UTF8 before adding any data, and obviously ensure that any data stored in the database is actually using UTF8 encoding when it is stored. Otherwise you end up having to specify every char/varchar/text/longtext etc field is using the correct encoding and collation settings.

Attempting to change such things on an existing database is a complicated task that needs thought and planning. Typically reading the existing data, converting the encoding and storing it back again. It is also vital to not have two, or more, applications that are using different encodings and storing data into the same database tables. Unless, obviously, you enjoy looking at every row / column in a database by hand and ensuring that the data is correctly encoded after the fact. (I’ll leave it to you to decide who had to do this. Thankfully it was a relatively small database) :frowning: .