Имя: Пароль:
1C
1С v8
При чтении из sqlite-базы с помощью ADO портятся данные
0 zelenprog
 
29.06.23
10:09
Здравствуйте!

Нужно в 1С8 загрузить данные из файла, которые представляет собой sqlite-базу.
Открываем базу с помощью ADO.

До недавних пор все работало нормально.
Но вот недавно в sqlite-базу добавили новое поле с типом "Строка" длиной 1000 символов.
И теперь, когда ADO читает это поле, команда "лНаборЗаписейАДО.Fields(лИмяКолонки).Value" возвращает строку с какими-то лишними символами-кракозябрами.

Например, в строке содержится: "(81122) 73-72-73            ". В конце много "пробелов" до 1000 символов.

ADO же возвращает: "(81122) 73-72-73                                                                                                                                                                                                                                                    È                                                                                                                                                                                                                                                                       È                                                                                                                                                                                                                                                                       È       "

Из-за чего такое происходит?
1 Волшебник
 
29.06.23
10:11
добавьте СтрЗаменить("È","") и СокрЛП
2 zelenprog
 
29.06.23
10:15
(1) Нет, проблема не в этом.
В самой базе строки нормальные. АДО их почему-то портит.

Если делать по вашему рецепту, то сначала ("È") будем менять, потом еще какие-то кракозябры.
Вряд ли таким способом получится привести строку к ее исходному виду.

Надо понять в чем проблема.
3 Волшебник
 
29.06.23
10:18
(2) Решайте проблемы по мере их поступления.
4 zelenprog
 
29.06.23
10:47
(3) Так ведь это и есть первая проблема - порча строки при чтении из базы.
Вот ее и решаем.
5 lEvGl
 
гуру
29.06.23
10:53
может драйвер поменять?
6 lEvGl
 
гуру
29.06.23
10:54
7 eklmn
 
гуру
29.06.23
11:01
(6) а это драйвер? ))
8 eklmn
 
гуру
29.06.23
11:02
(0) это не ты разрабатывал лерадатовский кусочек отрыжки?
9 lEvGl
 
гуру
29.06.23
11:10
(7) а что, нет разве?)
10 eklmn
 
гуру
29.06.23
11:24
(9) ODBC??
11 zelenprog
 
29.06.23
12:05
Драйвер я устанавливал как раз с этого сайта.
Причем совсем недавно, с месяц назад.
12 crasler
 
29.06.23
12:10
(11) Попробуй сделать дамп и загрузить в чистую бд файл
13 lodger
 
29.06.23
12:20
(11) а подключаешься через вот эту штуку? v8sqlite. Ошибка при подключении к базе
14 Chai Nic
 
29.06.23
13:18
Так данные в базе портятся или же криво выдаются? Это разные вещи.
15 zelenprog
 
29.06.23
13:47
(13) Нет. Через эту штучку не получилось.

Подключаюсь через стандартный драйвер, который скачал с сайта sqlite

    SQLiteObject = Новый COMОбъект("ADODB.Connection");
    SQLiteConnectionString = "DRIVER=SQLite3 ODBC Driver;Database=" + ФайлБД + ";";
    SQLiteObject.Open(SQLiteConnectionString);
    SQLiteRS = Новый COMОбъект("ADODB.Recordset");
    SQLiteRS = SQLiteObject .Execute(пЗапрос);
16 zelenprog
 
29.06.23
13:50
(14) >> Так данные в базе портятся или же криво выдаются? Это разные вещи.

Данные в базе нормальные.

Команда SQLiteRS.Fields("ФактАдрес").Value выдает "испорченную" строку.
17 zelenprog
 
29.06.23
13:56
Я записываю данные в sqlite-базу в 1С 7.7 с помощью 1sqlite и ТаблицыЗначений:

    лБаза = СоздатьОбъект("SQLiteBase");
    лБаза .Открыть("C:\Выгрузка.db");
    лЗапрос = лБаза .НовыйЗапрос();    
        лЗапрос.ВыполнитьЗапрос("pragma encoding='UTF-16'");

    лТЗ = СоздатьОбъект("ТаблицаЗначений");
    лТЗ.НоваяКолонка("ID", "Строка", 100);
    лТЗ.НоваяКолонка("Наименование", "Строка", 100);
    лТЗ.НоваяКолонка("ФактАдрес", "Строка", 200);
    лБаза .УложитьТЗ(лТЗ, "Контрагенты77", 1);

Я провел эксперимент. Оказалось, что проблема точно из-за длины строки.

Если в ТЗ указаны длины строк например 200 символов, то эти строки на стороне 1С8 читаются нормально.
Если в ТЗ указать длину строки например 1000 символов, то такая строка на стороне 1С8 читаются с кракозябрами.
18 zelenprog
 
29.06.23
13:57
Получается драйвер криво отрабатывает длинные поля в sqlite-базе?
Никто с таким не сталкивался?
19 Chai Nic
 
29.06.23
14:00
(18) А если в запросе данные урезать через CAST?
20 lEvGl
 
гуру
29.06.23
14:04
(18) сталкивался, но вопрос отпал и разбираться не стал
Recordset SQLite
21 Djelf
 
29.06.23
14:10
(0) Сама библиотека sqlite так устроена что чихать она хотела на тип данных в поле.
Т.е. несмотря на определенный тип в поля в него можно засунуть что угодно.
В каких-то последних релизах, вроде бы через pragma можно ужесточить такие вольности.

(15) Это не "стандартный" драйвер, стандартного драйвера не существует.
За корректность его работы, разработчики sqlite не несут ответственности.

(17) Интересно. А в 7.7 такие поля нормально читаются?
Тогда, да, виноват драйвер.
22 zelenprog
 
29.06.23
14:17
(21) >> Интересно. А в 7.7 такие поля нормально читаются?

Надо будет проверить. Пока не проверял.

И еще один косяк.
Все строки, записываемые из 7-ки в sqlite-базу, дополняются пробелами.
Например, записываю строку "12-34-56", а записывается "12-34-56                                    ".
Количество пробелов зависит от типа "Строка" и длины строки, установленного в колонке ТЗ.

Это тоже неудобно. Приходится при чтении, всегда обрезать.
23 lEvGl
 
гуру
29.06.23
14:23
фиксированная длина поля видимо
24 lodger
 
29.06.23
14:24
(22) подозреваю, что данные испорчены при записи, и в талдычке sqlite тоже какая-то х.
25 Djelf
 
29.06.23
14:30
(22) Только что проверил и ответил в теме https://www.1cpp.ru/forum/YaBB.pl?num=1214205575/1141#1141
Кратко: При выгрузке из 7.7 типизация "строка" в колонке тз требуется, количество символов не требуется (в том случае если строка переменной длины, а не какой-то жесткий идентификатор).
26 Djelf
 
03.07.23
08:43
Разобрался.
Суть в следующем: 1sqlite при выгрузке тз с колонкой Name в базу sqlite создает такую таблицу "CREATE TABLE t (Name not null)"
sqlite odbc сначала смотрит схему таблицы, и если в ней тип поля не varchar(1000), то типизирует как varchar(256)
Исправить можно вот так:

ALTER TABLE t ADD Name2 VARCHAR (1000);
UPDATE t SET Name2=Name;
27 orefkov
 
03.07.23
10:07
Дико пиарюсь^wизвиняюсь, но почему ADO, когда есть https://github.com/orefkov/v8sqlite?
Не пробовали?
28 orefkov
 
03.07.23
10:14
(22)
Просто не указывай длину строки в типе колонки, или вообще не задавай ей тип.
29 Djelf
 
03.07.23
10:22
(27) У него с этим проблема: v8sqlite. Ошибка при подключении к базе
У меня все нормально, правда на W10x64.

(28) Без VARCHAR(1000) не сработает, такой уж драйвер. http://www.ch-werner.de/sqliteodbc/html/index.html

Since May 25th, 2002, SQL_LONGVARCHAR is available but rather
experimental. That type is used for SQLite schema containing text
or varchar with a size specifier larger than 255.

The data type mapping obtains per-column meta information from the
"PRAGMA table_info(...)" SQLite statement. If SELECTs are used which
contain columns for which the table qualifier cannot be determined,
no meta information for data type mapping is available and therefore
the database source data type will be SQL_VARCHAR or SQL_LONGVARCHAR
which usually maps to SQL_C_CHAR.
30 orefkov
 
03.07.23
10:31
(29) Имхо всё-таки более правильно было бы разобраться, почему v8sqlite не работает. Лучше день потерять, потом за пять минут долететь :)
31 zelenprog
 
03.07.23
13:06
Спасибо, ребята!

(26) >> Исправить можно вот так:
>> ALTER TABLE t ADD Name2 VARCHAR (1000);
>> UPDATE t SET Name2=Name;

Где это нужно сделать?
Перед чтением данных в 1С8 с помощью ADO?
Или при записи данных в 1С77?

Может быть лучше перед записью данных в 1С77 явно создать колонку с нужным типом?
А потом уже сделать "уложение" ТЗ?

(30) >> Имхо всё-таки более правильно было бы разобраться, почему v8sqlite не работает. Лучше день потерять, потом за пять минут долететь :)
Я согласен.
Но я потратил уже больше дня. И так и не понял в чем причина.
Не подключается v8sqlite и все тут!
Думаю, что виновата моя Win11.
32 Djelf
 
03.07.23
13:33
(31) А уже нигде не надо ;) Забирай 1sqlite_3.42.0.30_draft4.zip https://cloud.mail.ru/public/9znr/ZJ6ULE9aR
+При укладке ТаблицыЗначений в том случае, если типизация колонки Строка и указана ее Длина поле в sqlite будет типироваться как varchar(длина).

Во всех предидущих версиях, как было указано выше, лучше при выгрузке, быстрее будет.

P.S. все таки используй формат базы utf-8, а не utf-16.
Самое медленное это запись на диск, а не преобразования туда сюда. А база в формате utf-16 раза в 4 больше, это существенно.
Можешь потестить скорость на приличном объеме, это не долго.
33 zelenprog
 
06.07.23
09:16
Какая вообще может быть максимальная длина строки в sqlite-базе?
А какая максимальная длина строки может быть в ТаблицеЗначений (интересно и для 1С 7.7 и для 8.3)?
34 lodger
 
06.07.23
10:06
(33) когда-то 1с признавалась, что кладёт мегастроки в ntext
https://its.1c.ru/db/pubapplied/content/329/hdoc/_top/ntext
а он в свою очередь вмещает maximum string length of 2^30 - 1 (1,073,741,823) bytes
https://learn.microsoft.com/en-us/sql/t-sql/data-types/ntext-text-and-image-transact-sql?view=sql-server-ver16
35 zelenprog
 
06.07.23
11:07
(34) А для строк переменной длины VARCHAR(n) есть какое-то ограничение?
36 Djelf
 
06.07.23
11:58
(35) 65536 см. SQL_LONGVARCHAR

/**
* Get maximum display size and number of digits after decimal point
* from field type specification.
* @param typename field type specification
* @param sqltype target SQL data type
* @param mp pointer to maximum display size or NULL
* @param dp pointer to number of digits after decimal point or NULL
*/

static void
getmd(const char *typename, int sqltype, int *mp, int *dp)
{
    int m = 0, d = 0;

    switch (sqltype) {
    case SQL_INTEGER:       m = 10; d = 9; break;
    case SQL_TINYINT:       m = 4; d = 3; break;
    case SQL_SMALLINT:      m = 6; d = 5; break;
    case SQL_FLOAT:         m = 25; d = 24; break;
    case SQL_DOUBLE:        m = 54; d = 53; break;
    case SQL_VARCHAR:       m = 255; d = 0; break;
#ifdef WINTERFACE
#ifdef SQL_WVARCHAR
    case SQL_WVARCHAR:      m = 255; d = 0; break;
#endif
#endif
#ifdef SQL_TYPE_DATE
    case SQL_TYPE_DATE:
#endif
    case SQL_DATE:          m = 10; d = 0; break;
#ifdef SQL_TYPE_TIME
    case SQL_TYPE_TIME:
#endif
    case SQL_TIME:          m = 8; d = 0; break;
#ifdef SQL_TYPE_TIMESTAMP
    case SQL_TYPE_TIMESTAMP:
#endif
    case SQL_TIMESTAMP:     m = 32; d = 3; break;
#ifdef SQL_LONGVARCHAR
    case SQL_LONGVARCHAR :  m = 65536; d = 0; break;
#endif
#ifdef WINTERFACE
#ifdef SQL_WLONGVARCHAR
    case SQL_WLONGVARCHAR:  m = 65536; d = 0; break;
#endif
#endif
    case SQL_BINARY:
    case SQL_VARBINARY:     m = 255; d = 0; break;
    case SQL_LONGVARBINARY: m = 65536; d = 0; break;
#ifdef SQL_BIGINT
    case SQL_BIGINT:        m = 20; d = 19; break;
#endif
#ifdef SQL_BIT
    case SQL_BIT:        m = 1; d = 1; break;
#endif
    }
    if (m && typename) {
    int mm, dd;
    char clbr[4];

    if (sscanf(typename, "%*[^(](%d,%d %1[)]", &mm, &dd, clbr) == 3) {
        m = mm;
        d = dd;
    } else if (sscanf(typename, "%*[^(](%d %1[)]", &mm, clbr) == 2) {
        if (sqltype == SQL_TIMESTAMP) {
        d = mm;
        }
#ifdef SQL_TYPE_TIMESTAMP
        else if (sqltype == SQL_TYPE_TIMESTAMP) {
        d = mm;
        }
#endif
        else {
        m = d = mm;
        }
    }
    }
    if (mp) {
    *mp = m;
    }
    if (dp) {
    *dp = d;
    }
}

37 zelenprog
 
06.07.23
17:20
А в программном коде 1С есть какое-то ограничение на длину строк в колонках ТаблицыЗначений с типом "Строка"?
38 lodger
 
06.07.23
19:26
(37) для 8ки кто-то изголялся в оперативке в переменной наращивая Строку неограниченную пошагово - оно сдыхало где-то на 20+ итераций, ближе или больше 1 млн значков. а тебе зачем столько?
39 zelenprog
 
07.07.23
08:19
(38) Просто интересно чисто теоретически
40 Djelf
 
07.07.23
08:33
(37) В ТаблицеЗначний нет строк, там ссылки на строки, а самих строк там нет.
41 DrZombi
 
гуру
07.07.23
08:38
(0) Скорей всего она их не портит. 1С если что-то не может показать, она это не показывает, но это не значит, что их там нет.
Обычно этот эффект можно добиться, к примеру простой загрузкой данных через режим "ОбменДанными.Загрузка = Истина".

Вы в поле с "1000" символами, можете записать символы, которые 1С не может пережевать на Тонком клиенте.
Выдавать глобальные идеи — это удовольствие; искать сволочные маленькие ошибки — вот настоящая работа. Фредерик Брукс-младший