LO Calc падает при обращении к sqlite_sequence БД SQLite из StarBasic

Автор ost, 29 апреля 2021, 06:31

0 Пользователи и 1 гость просматривают эту тему.

ost

Доброго.
Что-то делаю не так. Помогите, пож., разобраться.

Есть БД SQLite3. Код StarBasic обращается к ней посредством трансляции SQL-запросов ч/з БД ".odb", зарегистрированную в LO, и ODBC-драйвер версии 0.9998.00.00 отсюда http://www.ch-werner.de/sqliteodbc/.

В коде нужно определить количество и id новых записей, которые были вставлены в БД в ходе исполнения некого "куска" кода.
Для этого до и после исполнения "куска" запрашиваю значение поля "seq" из таблицы "sqlite_sequence" БД SQLite таким образом:

sSQL = "SELECT seq FROM sqlite_sequence WHERE name = """ & sTablNameInt &""""
oRs = MySet._CreateRowSet(DBName, sSQL)


При этом код корректно отрабатывает первый раз (до исполнения "куска"). При выполнении этого же кода после вставки записей в БД LO падает. Записи в ходе выполнения "куска" в БД вставляются корректно.

Функция "_CreateRowSet" в MySet выглядит так:

Function _CreateRowSet(sDBName, sSQLCommand as String)
'===Функция создает объект RowSet из имени базы и SQLкоманды
RowSet = createUnoService("com.sun.star.sdb.RowSet")
RowSet.DataSourceName = sDBName
RowSet.CommandType = com.sun.star.sdb.CommandType.Command
RowSet.EscapeProcessing=False

RowSet.Command=sSQLCommand
RowSet.execute() ' выполняем
_CreateRowSet=RowSet
End Function '_CreateRowSet


На борту:
Version: 7.1.1.2 (x64) / LibreOffice Community
Build ID: fe0b08f4af1bacafe4c7ecc87ce55bb426164676
CPU threads: 4; OS: Windows 6.1 Service Pack 1 Build 7601; UI render: Skia/Raster; VCL: win
Locale: ru-RU (ru_RU); UI: ru-RU
Calc: CL

SQLite3:
3.35.4


economist

#1
1) Зачем запрашивать весь столбец seq, когда "дешевле" запросить max(seq) ?

2) Для определения количества и id новых записей до/после - можно считать всегда имеющееся готовое поле max(ROWID) до и после вставки

3) Попробуйте не-литералы обрамлять ' вместо "" - так код чище, SQLite позволяет.

sSQL = "SELECT seq FROM sqlite_sequence WHERE name = " '" & sTablNameInt &"' "

Но ваш код чистый, падать не должно. Самые частые падучие ситуации с Base, имхо, это запрос полей по индексу за пределами имеющихся.
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

ost

#2
economist,
благодарю за ответ и замечания.

Поправил так:

sSQL = "SELECT max(ROWID) FROM " & sTablNameInt


Результат тот же. LO падает на втором по счету запросе (после вставки записей в БД) на строке
RowSet.execute() ' выполняем
функции "_CreateRowSet" из MySet.
У меня включена поддержка внешних ключей. Возможно что-то здесь. Хотя я не понимаю, как это может быть связано.
Записи в БД вставляются корректно. =(

UPD
А можно ли "обнулить" объект RowSet? И как?
Отвечу. Видимо, так "oRs = Nothing"

UPD
"оRs = Nothing", а так же отключение от БД и повторное подключение к ней перед вторым запросом не помогают.

kompilainenn

Поддержать разработчиков LibreOffice можно тут, а наш форум вот тут

ost

Не понимаю даже где проблема. В БД или в кривых руках, или в LO.

economist

Покажите свои картинки вот этого (вложения):
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

economist

Рекордсет RowSet - странная штука, способная изумлять. Попробуйте подвигать курсор перед вторым запросом (по одному варианту):

RowSet.beforefirst()
RowSet.first()
RowSet.next()
RowSet.last()

Вы также можете узнать число строк в нём прямо в Basic: RowSet.RowCount()
Также можно прочесть без "переусложнения" SQL - заголовок поля и его значение в текущей строке:

RowSet.Columns(0).Name ' заголовок 0-го поля
RowSet.getString(1) ' значение 0-го поля (хотя стоит 1 ???)
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

ost

#7
Цитата: economist от 29 апреля 2021, 11:14Покажите свои картинки

Попробовал сейчас релизы LO 7.1.2 и 7.0.5. В обоих случаях  - падения на упомянутой строке.




ost

Цитата: economist от 29 апреля 2021, 11:26Попробуйте подвигать курсор перед вторым запросом
А имеет ли это смысл, поскольку делал перед вторым запросом:
"оRecordSet = Nothing", а так же отключение от БД и повторное подключение к ней?

economist

Имеет, потому что оRecordSet = Nothing лучше убрать и проверить многократное срабатывает первого запроса.
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

ost

RowSet.beforefirst() не помогло.
Если закомментировать второй запрос. Весь код всегда выполняется успешно. Данные в БД вставляются.

mikekaganski

Цитата: ost от 29 апреля 2021, 06:31LO падает
Цитата: kompilainenn от 29 апреля 2021, 10:46
Не поленитесь запилить баг репорт
Цитата: ost от 29 апреля 2021, 11:01
Не понимаю даже где проблема. В БД или в кривых руках, или в LO.

LO падает никогда не бывает из-за "кривых рук". Программа не должна падать. Проблема может быть в ЛО, или в драйверах БД (если они загружаются в программу).
Пожалуйста, последуйте совету kompilainenn. Вы уже столько тут дискутируете, а если бы был пример БД с кодом, который можно было бы запустить, я уже давно бы нашёл, где сбой (не факт, что исправил бы, но по крайней мере ситуация была бы ясна). И может быть, посоветовал бы, как обойти. Но ведь дискутировать вокруг чёрного ящика интереснее, верно? ;)
С уважением,
Михаил Каганский

economist

#12
Еще можно попробовать вместо второго запроса обратиться к БД через Statement (всё равно создается recordset, но он точно другой):

DatabaseContext = createUnoService("com.sun.star.sdb.DatabaseContext")
DataSource = DatabaseContext.getByName("ИМЯБАЗЫ") ' указать!
Connection = DataSource.GetConnection("", "")   
Statement = Connection.createStatement()
rs = Statement.executeQuery("SELECT max(seq) FROM sqlite_sequence")
rs.next()
msgbox rs.getString(1)


UPD: Воссоздал ситуацию у себя и понял что вставка новых строк "портит" прежний RowSet, при обращении к нему возникает ошибка (у меня либра не падает). То есть нужно после вставки:
1) пересоздать заново RowSet
2) шагнуть в него RowSet.next()

Следующий псевдокод (некогда) у меня отработал без ошибок:

RowSet = Statement.executeQuery("SELECT max(ROWID) FROM ЗАЯВКИ")
RowSet.next()
msgbox RowSet.getString(1) ' ок
Statement.executeUpdate("INSERT INTO ЗАЯВКИ (Материал, Марка) VALUES ('123', '123')")
RowSet = Statement.executeQuery("SELECT max(ROWID) FROM ЗАЯВКИ")
RowSet.next()
msgbox RowSet.getString(1) ' ок


Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

ost

#13
Цитата: mikekaganski от 29 апреля 2021, 13:24Но ведь дискутировать вокруг чёрного ящика интереснее, верно?
Не верно. Но, "как есть" выложить в общий доступ не могу. Чтобы "навести анонимность" нужно потратить время. На корректировку базы, кода, и пр.
Мне показалось, что затраты времени (коего сейчас крайне мало) не оправданы, тем более, что вопрос касался, как мне казалось, моей элементарной ошибки в коде. Видимо, моя оценка была не верна (ибо не программист от слова совсем), поэтому и диспут.
Стараюсь, по-возможности, разобраться сам. Пользуюсь, конечно, знаниями и опытом участников форума. Благодарен. Отдельное спасибо, economist'у за терпение и толковые предложения. Постараюсь выложить пример базы и кода. Позже. Если не получится как то решить проблему.

ost

Цитата: economist от 29 апреля 2021, 13:36Следующий псевдокод (некогда) у меня отработал без ошибок:
У меня тоже. Супер! Спасибо.