Страницы: 1
Люди добрые, подскажите, кто знает.
Решил я немного повысить функциональность окна истории посещений и в процессе своих ковыряний обнаружил в places.sqlite в таблице moz_places странные записи. У них в поле last_visit_date стоит совершенно нормальная (и даже правдоподобная) дата, но при этом в поле visit_count стоит 0.
И таких записей у меня там нашлось аж три десятка.
Потом уже, глядя на URL-ы в этих записях, я выяснил, что и браузер в своём окне истории их показывает. И если столбец "Число посещений" сделать видимым, то оказывается, что у всех прочих записей там стоит число, а у этих - пустое место.
Вопрос: Является ли наличие подобных записей нормальным или это последствия каких-то сбоев в работе с БД? И если это нормально, то как подобные записи образуются?
Отсутствует
Нет, я не с закладками разбираюсь, а с историей посещений.
Понятно, что таблица moz_places общая для всего, но те ссылки я никогда в закладки не помещал. Это совершенно точно.
Пока склоняюсь к мысли, что это последствия зависаний браузера и его последующего убивания через Диспетчер задач. Но в этом предположении слишком много "если" и "может быть".
Отсутствует
Вопрос: Является ли наличие подобных записей нормальным
Ну, раз загрузки могут образовывать подобные записи,
то, как минимум, их наличие нельзя назвать совсем уж не нормальным.
Отсутствует
Ну, раз загрузки могут образовывать подобные записи
А вот это вопрос интересный. У меня же Iceape (Seamonkey), а там загрузки лежат в отдельном файле - downloads.sqlite. И счётчика посещений у них нет.
Но для нулевого счётчика у Firefox-овых загрузок хотя бы смысл и механизм понятен - они в historyvisits не пишутся, и frecency для них считать незачем. А тут посещения...
Тогда возможно рефереры, ну типа переходишь по ссылке, а там перенаправление.
Я вчера вечером выделил время и заново посетил все эти ссылки. Нет, всё честно, никаких перенаправлений. Максимум, "Домен не существует" или "Страница не существует". Но раз в places.sqlite у них записан title, то значит тогда по этому адресу открылась именно страница.
Да, и ещё один нюанс: у Seamonkey, в отличие от Firefox, те URL-ы, которые ответили перенаправлением, в базу данных вообще не попадают.
Поэтому текущая (сомнительная) гипотеза такая: браузер перед зависанием успел внести запись в moz_places, но не успел в moz_historyvisits. А потом какой-то внутренний процесс (возможно, подсчёт frecency) пересчитал записи в historyvisits и внёс актуальное значение (ноль) в moz_places.
Dumby
Моя затея с расширением для улучшения окна истории оказалась несколько сложнее, чем представлялось изначально. Похоже, что слишком много собственного кода браузера придётся подменять своим.
Если самому с чем-то справиться не удастся, можно за помощью обратиться? Осталось ещё что-то в памяти о XUL-расширениях?
Отредактировано yup (18-02-2025 15:25:07)
Отсутствует
Если самому с чем-то справиться не удастся, можно за помощью обратиться?
Обратиться-то можно, но будет ли от этого толк?
Плюс, надо ссылку на этот, такой же как у тебя, Iceape.
Даже если скачается и встанет, то он будет у меня в оффлайн-среде.
Но тогда, хотя бы будет предмет для обсуждения.
XUL-расширениях
Нет такого понятия.
Были оверлейные расширения.
Ещё, были расширения системы «Афёра SDK».
Были и есть bootstrapped расширения.
Сейчас, в Firefox, есть ещё странная разновидность
расширений, именуемая WebExtensions Experiments.
Отсутствует
Обратиться-то можно, но будет ли от этого толк?
Вот я и спросил - будет ли?
Я в разные периоды своей жизни разными делами занимался, от многих из них в голове только смутные воспоминания остались.
Плюс, надо ссылку на этот, такой же как у тебя, Iceape.
Не обязательно. Я под него перенёс с полсотни расширений и кнопок CustomButtons от Seamonkey. Процентов 80 из них не потребовали вообще никаких изменений, только новый ID в install.rdf записать. А у большинства из оставшихся 20% - этот же ID добавить в chrome.manifest.
То есть, совместимость с SM 2.49 очень высокая. (Я для Iceape и всех остальных основанных на UXP программ DOM Inspector адаптировал и ещё кучку исследовательских расширений, поэтому потроха изучил основательно.)
И обновления браузера (а они довольно часто выходят) ни разу ничего не поломали.
А сама программа берётся здесь: https://o.rthost.win/hbl-uxp/index.php? … &order=asc
Даже если скачается и встанет, то он будет у меня в оффлайн-среде.
Ну так для работы с историей доступ к Интернету не требуется. Я даже places.sqlite подкину, если что. Хотя там вопросы предвидятся типа: "Как вот из этого места кода достучаться до вон той функции?"
Нет такого понятия.
Официально нет.
Потому что сначала только такие и были. Потом появились другие - им названия дали, чтобы отличать. А этим так и не удосужились.
А как-то же сейчас называть надо. "Оверлейные расширения" тоже ведь не совсем официальное название. Поэтому приходится между собой договариваться. Каждому микросообществу в отдельности.
Были и есть bootstrapped расширения.
Сейчас, в Firefox, есть ещё странная разновидность расширений, именуемая WebExtensions Experiments.
А разве bootstrapped в нынешнем FF поддерживаются? Я думал, от всего "проклятого прошлого" давно отреклись в угоду WebExtensions.
Отредактировано yup (18-02-2025 20:00:01)
Отсутствует
Скажу более… настройки — Cookies — Управление данными…
В этом окне можно увидеть "кол-во Cookies" = 0, однако РАЗМЕР может доходить в несколько МЕГАБАЙТ!
Отсутствует
T0PMØ3iLLA
Они ж в SQL-ной базе данных хранятся. А это как MFT у NTFS: когда много записей добавляется - растёт; когда записи удаляются - не уменьшается.
Операция уменьшения ("vacuum") в браузере есть, но, по-моему, она там только вручную запускается.
Впрочем, браузеров развелось много разных, за всеми не уследишь.
Ну, и минимальный размер у некоторых из этих файлов совсем не маленький. Даже у абсолютно пустых, свежесозданных.
(У меня всю жизнь в настройках политика обращения с куками - "удалять по завершении сеанса". А у файла cookies.sqlite размер сейчас полмегабайта. Но это же не значит, что в нём столько хранится. С точки зрения движка SQLite он практически пустой.)
Отредактировано yup (18-02-2025 21:22:47)
Отсутствует
Вот я и спросил - будет ли?
Откуда же мне знать не видя вопроса, тут не угадаешь.
программа берётся здесь
Фух, скачал 52.9.20250206, развернул, запихал CB и DOMi, можно смотреть.
Так вот, система-то оффлайн, но есть прога Wampserver,
в которой я совсем ничего не понимаю,
но могу HTML'ки на диске размещать так,
что браузер отображает их как настоящие http-страницы.
Открываю вкладку, набираю адрес, страница открывается.
В базе: last_visit_date — есть, visit_count — единица.
Теперь, Ctrl+H, ПКМ —> «Delete»
В базе: запись просто исчезает. Из окна «History» тоже.
Теперь, ПКМ по этой странице —> «Save Page As…», сохраняю.
И вот оно!
В базе: last_visit_date — есть, visit_count — ноль.
И в окне «History» строка есть. С пустой графой «Visit Count».
Кстати, на странице есть ссылка.
Если ПКМ по по ней —> «Save Link Target As…»,
то снова получается подобная запись.
Это я не к тому, что у тебя они именно так и образовались,
а к тому, что такое возможно в принципе, и без каких-либо сбоев.
А как-то же сейчас называть надо.
Да, ты всё верно говоришь.
Просто название «XUL-расширение» какое-то дурацкое.
Если имеется в виду как разновидность расширения,
то не подходит, поскольку можно представить
оверлейное расширение вообще без XUL'а,
и bootstrap расширение, которое навалит целый вагон XUL'а.
А если имеется в виду как противопоставление WebExtensions,
тогда избыточно, поскольку WE расширениями не являются.
Это совершенно отдельный вид дополнений,
а официально такими именуются лишь в пропагандистских целях.
То есть, либо WebExtensions, либо просто «расширение».
Ну, таково моё мнение, которое, впрочем, да и вообще, не важно.
А разве bootstrapped в нынешнем FF поддерживаются?
Конечно нет. И уже давно. Но засунуть можно.
Самих расширений, наверно, немного, но они существуют.
Отсутствует
Откуда же мне знать не видя вопроса, тут не угадаешь.
А я напишу. Всю историю - от первоначальной задумки до той ситуации, до которой я сейчас "докатился". Но чуть позже - чтобы это отдельным сообщением было.
Теперь, ПКМ по этой странице —> «Save Page As…», сохраняю.
И вот оно!
В базе: last_visit_date — есть, visit_count — ноль.
Да уж... Ну и где логика (разработчиков)? (На всякий случай: это я сейчас в Iceape сижу, но используемый places.sqlite унаследован от Seamonkey, и записи в нём копились лет 20. А эти "обнулённые" и очень старые нашлись, и совсем свежие, буквально позавчерашние.)
Кстати, на странице есть ссылка.
Если ПКМ по по ней —> «Save Link Target As…», то снова получается подобная запись.
Ну ладно, это ещё как-то понять можно - фактически страницу не посещали.
Но сбрасывать в 0 счётчик при сохранении в файл текущей страницы???
Но теперь мне надо эту новость обдумать и поизучать ситуацию самому.
А пока объясню, почему возник интерес к этим нулям.
Я пока пришёл к тому, что для реализации моей идеи придётся самому формировать SQL-ный запрос к БД и самому заполнять окно истории. А выяснить, какой запрос туда уходит от штатного кода, не удалось. Пришлось экспериментировать. Первый заезд был с очевидным условием: visit_count > 0. Записей вернулось в несколько раз больше, чем показывает окно истории.
Посмотрел на эти записи, увидел, что у многих стоит hidden = 1. Что это hidden означает, не знаю, но добавил в запрос NOT hidden. Получил чуть-чуть меньше записей, чем в окне истории.
Тогда просто сохранил в один текстовый файл URL-ы из моего запроса, в другой - URL-ы из окна истории, и сравнил их. А потом нашёл в БД эти записи и прикинул, чем они отличаются от "нормальных", после чего заменил visit_count > 0 на last_visit_date <> 0. В результате, наконец, получил точное совпадение.
Всё. В том смысле, что к этим нулям я прицепился только из дотошности - хочу, чтобы показываемая моим кодом история содержала ровно те же записи, что и в штатном случае.
А к главным проблемам всё это отношения не имеет.
Да, ты всё верно говоришь.
Просто название «XUL-расширение» какое-то дурацкое.
Но тут такая ситуация:
1. Название "оверлейные расширения" ссылается на те же самые XUL overlays, что и название "XUL-расширения".
2. Я "за рулём" компьютеров с 70-х годов. И тогда, и в 80-е, и в начале 90-х в программировании широко использовались термины "оверлеи" и "оверлейные программы". Причём эти понятия не имели никакого отношения к UI, а описывали особенности внутреннего устройства самих программ.
И сидит во мне это настолько крепко, что даже сейчас назвать мозилловские расширения оверлейными у меня "язык не поднимается".
Если имеется в виду как разновидность расширения, то не подходит, поскольку можно представить оверлейное расширение вообще без XUL'а
Разве? По-моему, как минимум один файл .XUL должен быть, пусть даже и не меняющий ничего во внешнем виде. Иначе как код расширения запускаться будет?
(Вариант, когда в расширении только новая служба имеется, рассматривать не будем - слишком уж экзотический случай.)
Отредактировано yup (19-02-2025 01:26:10)
Отсутствует
Я про размер не самого файла базы данных, а конкретно про столбец Storage в окне Firefox (как со столбцом кол-ва посещений у истории) — тоже пишет в мегабайтах, хотя у столбца “Cookies” слева показывает значение 0:
data:image/png;base64,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
Кусты реестра SOFTWARE тоже у мн. пользователей за полсотню метров "растягивались" из-за каких-то несчастных пары значений в Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage (ошибка загрузки счётчиков в perfmon.msc), занявших десятки мегабайт — lodctr /r хоть и исправило данные (соответственно, размер там стал куда более адекватным), но сам куст SOFTWARE так и остался за полсотню метров… А использовать "оптимизаторы реестра" опасно, т.к. фрагментироваться новые данные станут сильнее — знать бы, как это всё перераспределить (дефрагментировать) вручную, оставив ещё разряжённые участки между определёнными подразделами…
А про NTFS… ну… моё мнение по этому поводу уж слишком оффтопное выходит
Отредактировано T0PMØ3iLLA (19-02-2025 21:56:59)
Отсутствует
конкретно про столбец Storage в окне Firefox (как со столбцом кол-ва посещений у истории) — тоже пишет в мегабайтах, хотя у столбца “Cookies” слева показывает значение 0
Что ещё за «хотя»?
Столбец «Cookies» — это количество кук.
Столбец «Storage» — это что-то типа попытки подсчёта добра, которое видно по Shift+F9
Оконце ведь называется «Manage Cookies and Site Data»,
а не просто «Manage Cookies».
Отсутствует
Ну вот, собрался с силами и попытаюсь описать, в чём состояла затея и до чего я докатился.
А обратное, увы, невозможно: когда я смотрю на любую запись в окне истории, я никак не могу определить, есть ли у меня закладка с таким URL или нет.
И даже пункт меню "Добавить в закладки" активен в том числе и на URL-ах, которые в закладках уже есть, и не моргнув глазом даёт возможность добавить их туда ещё раз.
Вот это безобразие и хочется устранить.
И реализация представлялась несложной. Есть XUL окна (chrome://communicator/content/history/history.xul) с этой таблицей, программно добавляем в эту таблицу новый столбец.
Находим функцию, которая получает из базы данных записи для этой таблицы, смотрим запрос, создаём свой модифицированный вариант и изыскиваем способ подменить или запрос, или функцию.
А нижележащие функции, которые вызываются, это History API, в котором нет ничего в данном случае полезного. Там можно управлять перечнем запрашиваемых полей, но выбор только из жёстко заданного набора, в котором ничего подходящего для меня нет.
Сначала Places API обнадёжило: оказалось, что у каждом возвращаемой записи истории есть поле bookmarkIndex. Я обрадовался, решив, что это индекс в таблице moz_bookmarks, и значит, если у записи там стоит осмысленное число, то закладка есть. Но эксперимент показал, что для всех записей из моей истории там возвращается -1, хотя многие из них в закладках точно имеются.
А критический взгляд на описание этого поля в документации показал, что описание это неоднозначное, и прочитать его можно по-разному - в зависимости от того, как хочешь его прочитать.
Затем из документации выяснил, что поле itemId у результатов это тоже индекс в закладках. Правда, для моих записей в нём тоже всегда -1 стоит. И да, его описание тоже можно прочитать по-разному, было бы желание.
Прошёл отладчиком дальше (в смысле - ниже) и добрался в конце концов до вызова Сишной функции, но формирования запроса, который можно было бы модифицировать, так и не встретил.
Значит, он где-то в Сишном коде, а его своим расширением не подменишь.
Сначала подобрал запрос к moz_places, дающий такой же результат, как и штатный код (именно тогда и возник вопрос о нулях).
Потом добавил к запросу заглядывание в таблицу moz_bookmarks. Результат получился правильным.
А потом обнаружил, что привлекать moz_bookmarks не требуется, потому что поле foreign_count в записях moz_places это счётчик, указывающий, сколько раз URL из записи встречается в закладках.
То есть, так получается не только быстрее, но даже и круче, чем хотелось изначально - перед глазами будет не просто плюсик, а счётчик.
Для ковыряния в истории SQL-запросами в Places API есть парочка функций, унаследованных от Storage API:
А последнее предложение в п.2 неплохо сочетается с двумя нюансами, которые тоже хочется использовать:
Очень хочется преобразовать то, что возвращает executeAsync(), в то, что можно скормить PlacesTreeView внутри load(), и таким образом обойтись только навешиванием своей простейшей надстройки над getCellText() из chrome://communicator/content/history/treeView.js
Вот над этим сейчас голову и ломаю (по мере наличия времени).
Отредактировано yup (22-02-2025 03:08:01)
Отсутствует
yup
Какое восхитительное описание! Доходчиво и подробно.
Даже слишком, не уверен, что я смогу прямо сходу это дочитать.
Но прокомментирую.
Желание же самое простое: добавить в таблицу, где история отображается, ещё один столбец, в котором как-нибудь (да хоть просто плюсиком) будет обозначаться наличие посещённой страницы в закладках.
И реализация представлялась несложной.
Трудность внезапно всплыла с запросом.
Странные у тебя понятия о простом и сложном.
И вообще, тут как бы ожидался, собственно, код, добавляющий столбец.
Полная версия реализации. Если расширением, значит в base64 или https://www.upload.ee
(ну, знаешь, типа «нет кода — нет разговора»).
В столбце — что угодно, например, случайное число.
В коде — коммент-слот а-ля «// Здесь надо получить текст столбца».
Ладно, для начала, рассмотри вариант.
В базу не полезу, если не убедишь в необходимости.
Чесать репу над колонкой не буду, в надежде, что у тебя есть готовый код.
Вот демо-набросок.
Открываем вкладку с адресом chrome://communicator/content/history/history.xul
На ней, вызываем веб-консоль (Ctrl+Shift+K).
С js-терминала консоли запускаем код.
Ожидаемый результат: в колонке «Location»
урлы, имеющиеся в закладках, будут красным болдом.
Ну, это если у тебя никакой сторонний код не претендует на переопределение
PlacesTreeView.prototype.getCellProperties(), иначе возможен конфликт.
(() => { // Shortcuts var bkd = "bookmarked"; var uri = Services.io.newURI; var bms = PlacesUtils.bookmarks; var rtu = Components.interfaces.nsINavHistoryResultNode.RESULT_TYPE_URI; // CORE! var isb = bms.isBookmarked; // Redef getCellProperties() var proto = PlacesTreeView.prototype, {getCellProperties} = proto; proto.getCellProperties = function PTV_getCellProperties(aRow, aColumn) { if (aColumn.id == "URL") { var node = this._getNodeForRow(aRow); return node.type == rtu && isb(uri(node.uri)) ? bkd : ""; } return getCellProperties.call(this, aRow, aColumn); } // Style var css = ` treechildren::-moz-tree-cell-text(${bkd}) { color: red !important; font-weight: bold !important; } `.trim(); document.firstChild.before(document.createProcessingInstruction( "xml-stylesheet", `href="data:text/css,${encodeURIComponent(css)}" type="text/css"` )); // Def invalidate var inv = gHistoryTree.treeBoxObject.invalidate.bind(gHistoryTree.treeBoxObject); inv();// Apply immediately // Observer var obj = Object.create(null); obj.QueryInterface = XPCOMUtils.generateQI([Components.interfaces.nsINavBookmarkObserver]); var obs = new Proxy(obj, {get: (trg, name) => trg[name] || inv}); bms.addObserver(obs, false); addEventListener("unload", () => bms.removeObserver(obs), {once: true}); })();
Отредактировано Dumby (23-02-2025 02:42:48)
Отсутствует
Странные у тебя понятия о простом и сложном.
Ну так:
Добавить столбец в окошко таблицы на экране - раз плюнуть.
Данные хранятся в файле .sqlite, значит добываются они оттуда с помощью SQL-запроса. Запрос, который будет возвращать нужные для нового столбца данные, сформировать тоже труда не составляет.
Таково было первоначальное представление - до того, как внутрь полез.
И вообще, тут как бы ожидался, собственно, код, добавляющий столбец.
Если нужно, код я изображу. Просто у меня есть изрядный опыт работы с элементом <tree>, и поэтому вопросов по визуальной части затеи не предвидится, все изыскания - как бы данные, получаемые из places, так оформить, чтобы их было удобно в этот элемент засунуть.
А несколько способов добавить столбец в таблицу вот (без оглядки на то, насколько тот или иной применим в данном случае):
1. У <tree> (таблицы) есть дочерний элемент <treecols> (шапка), а у <treecols> есть метод appendChild(), позволяющий добавлять в таблицу новые столбцы (<treecol>) и разделители между ними (<splitter>).
2. Таблица истории со всеми её столбцами описана в файле history.xul, который открывается по команде из меню. Расширение может заменить код этой команды на свой, который будет открывать другой .xul вместо штатного.
3. Элемент <tree> динамический. Если в нём уже есть какие-то строки и добавляется новая строка, имеющая поле, которого не было у предыдущих, то столбец для этого поля добавится автоматически.
В общем, как изменить внешний вид таблицы, вопросов нет и не предвидится. И вообще я пока вопроса никакого не задал, а просто обрисовал, что затеял и чем сейчас занимаюсь: перебираю варианты, которыми можно полученные результаты запроса подсунуть в качестве исходных данных для таблицы.
А эти результаты сами по себе штука занятная. Вот элементарный код:
var sql = 'SELECT * FROM moz_places'; var sql_stmt = Components.classes['@mozilla.org/browser/nav-history-service;1'] .getService(Components.interfaces.nsPIPlacesDatabase) .DBConnection .createStatement(sql); sql_stmt.executeStep(); var resultRow = sql_stmt.row; console.log(resultRow); sql_stmt.reset();
Вот что получается в консоли:
А теперь после console.log(resultRow) добавляю строки:
console.log(resultRow.id); console.log(resultRow.url); console.log(resultRow.hidden);
И вот что в консоли теперь:
Смотрим на правую часть окна - какие там интересные значения у всего, и какие интересные изменения произошли в структуре объекта-результата. "А ведь ничего не сделал, только вошёл..."
Так что пока исследую штатный код, заполняющий таблицу и потом всячески с ней работающий, чтобы решить, что проще и безопаснее - преобразовать это чудо (StatementRow) в тот тип, с которым код работает сейчас, или заменить код своим, ориентированным именно на StatementRow.
это если у тебя никакой сторонний код не претендует на переопределение
PlacesTreeView.prototype.getCellProperties(), иначе возможен конфликт.
То, что существуют конфликтующие друг с другом расширения - не секрет. Но для окна расширений практически нет. А те, которые есть, либо совместимыми, скорее всего, окажутся, либо настолько несовместимы по назначению, что никто такую пару одновременно ставить не станет.
Добавлено 23-02-2025 17:53:00
А что касается "выделения красным" - я думал о чём-то подобном, но решил, что если интересующие строки предстоит в длинном списке выискивать глазами, то пометки, стоящие в отдельном столбце, высматривать будет легче. А сейчас ещё и счётчик нашёл...
Плюс к тому, по столбцу и отсортировать можно.
Ну, и скорость. Это я историю по несколько раз в день чищу. А есть люди, которые годами этого не делают - принципиально. А тут для каждой записи отдельный запрос делается. В то время как всё сразу можно было бы получить одним запросом.
Попробую раздобыть чужой нечищенный places.sqlite - посмотрю, какая скорость получается.
Upd:
До полей с неизвестными заранее именам в результатах SQL-ного запроса добираются вот так:
var sql = 'SELECT * FROM moz_places'; var sql_stmt = Components.classes['@mozilla.org/browser/nav-history-service;1'] .getService(Components.interfaces.nsPIPlacesDatabase) .DBConnection .createStatement(sql); var colCount = sql_stmt.columnCount; var columnNames = Array(colCount); for (var i = 0; i < colCount; i++) { columnNames[i] = sql_stmt.getColumnName(i); } sql_stmt.executeStep(); var resultRow = sql_stmt.row; for (var i = 0; i < colCount; i++) { columnName = columnNames[i]; console.log(columnName + ' = ' + resultRow[columnName]); } sql_stmt.finalize();
Теперь уже более-менее понятно, как это таблице подсовывать.
(Я ж почему к этим именам так прицепился: хотелось свой довесок сделать универсальным, чтобы мог работать с результатами любого запроса, а не только строго фиксированным набором полей, как в оригинале.)
Отредактировано yup (24-02-2025 01:27:29)
Отсутствует
вопросов по визуальной части затеи не предвидится
Не, это я, скорее, к тому, чтобы мне взять
уже готовый код, а не сочинять самому.
Так же, даёт возможность проникнуться концепцией в целом.
Вот что получается в консоли
Да, вижу. Действительно странно.
Ну, и скорость.
тут для каждой записи отдельный запрос делается. В то время как всё сразу было бы получить одним запросом.
Я тут попробовал сочинить тестовый код.
Ну, как смог, SQLite-то я не знаю.
Суть: получить объект, где свойства — урлы истории,
а значения — количество штук в закладках.
Ну и замерить сколько на это уйдёт времени.
Запускал на Firefox 56, places.sqlite — 65 мегабайт.
Находит где-то 69 тысяч урлов.
Выигрывает практически всегда TEST_SQL_AGG_NATIVE
а TEST_XPCOM всегда последний.
Кстати, наткнулся на такое:
Обнаружился один урл, для которого foreign_count
не совпадает с тем, что отдаёт TEST_XPCOM
В базе значение — три,
а кодом без использования чтения базы — два.
Оказалось, что добавление к закладке tag'а (метки)
увеличивает foreign_count на единицу.
Видимо, PlacesUtils.bookmarks.getBookmarkIdsForURI()
отдаёт результат без учёта папки меток.
А вот на Iceape — там для такой закладки совпадает,
то есть метки учитываются.
И ещё, у меня там чаще выигрывает TEST_SQL_WHILE_LOOP
наверно из-за мизерного размера базы.
(() => { var ts = Components.utils.now; var conn = PlacesUtils.history.DBConnection; var from = " FROM moz_places WHERE hidden = 0 AND last_visit_date NOTNULL"; var testFunctions = [ function TEST_XPCOM() { var query = PlacesUtils.history.getNewQuery(); var options = PlacesUtils.history.getNewQueryOptions(); options.queryType = Components.interfaces.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY; var u = Services.io.newURI; var bids = PlacesUtils.bookmarks.getBookmarkIdsForURI; var result = {}; var now = ts(); var {root} = PlacesUtils.history.executeQueries([query], 1, options); var wasClosed = !root.containerOpen; if (wasClosed) root.containerOpen = true; for(var ind = 0, max = root.childCount; ind < max; ind++) { var {uri} = root.getChild(ind); result[uri] = bids(u(uri)).length; } if (wasClosed) root.containerOpen = false; return [result, ts() - now]; }, function TEST_SQL_WHILE_LOOP() { var sql = "SELECT url, foreign_count" + from; var statement = conn.createStatement(sql); var result = {}; var now = ts(); while(statement.executeStep()) { var {row} = statement; result[row.url] = row.foreign_count; } statement.finalize(); return [result, ts() - now]; }, function TEST_SQL_AGG_CUSTOM() { var url, onFinal = () => {}; conn.createAggregateFunction("agg_url", 1, { onFinal, onStep: args => url = args.getString(0) }); conn.createAggregateFunction("agg_foreign_count", 1, { onFinal, onStep: args => result[url] = args.getInt32(0), }); var sql = "SELECT agg_url(url), agg_foreign_count(foreign_count)" + from; var statement = conn.createStatement(sql); var result = {}; var now = ts(); statement.executeStep(); statement.finalize(); conn.removeFunction("agg_url"); conn.removeFunction("agg_foreign_count"); return [result, ts() - now]; }, function TEST_SQL_AGG_NATIVE() { var sql = "SELECT group_concat(url, '\n') urls, group_concat(foreign_count, '\n') fcs" + from; var statement = conn.createStatement(sql); var result = {}; var now = ts(); statement.executeStep(); var {urls, fcs} = statement.row; statement.finalize(); var num = 0; fcs = fcs.split("\n"); for(var url of urls.split("\n")) result[url] = +fcs[num++]; return [result, ts() - now]; } ]; var sort = (a, b) => a.num - b.num; var pad = Math.max(...testFunctions.map(f => f.name.length)) + 2; // Set random order for(var func of testFunctions) func.num = Math.random(); testFunctions.sort(sort); var prevResult, prevName, output = [], num = 1; for(var func of testFunctions) { var {name} = func; var [result, time] = func(); if (prevResult) { var keys = Object.keys(result); var prevKeys = Object.keys(prevResult); if (keys.length != prevKeys.length) { console.log( "Not same result length!\n" + `${name}: ${keys.length}\n${prevName}: ${prevKeys.length}` ); throw "So, test failed"; } for(var key of keys) if (result[key] !== prevResult[key]) console.log( `Not same value for ${key}\n` + `${name}: ${result[key]}\n${prevName}: ${prevResult[key]}` ); } else output.push(Object.keys(result).length + " urls"); prevName = name; prevResult = result; var str = new String(num++ + " " + name.padEnd(pad, " ") + time); str.num = time; output.push(str); } // Sort out output.sort(sort); console.log("\n" + output.join("\n")); })();
sql_stmt.finalize();
Да, точно, finalize()
А то я reset() как-то бездумно у тебя срисовал
из предыдущего кода про sql_stmt. Поправил.
Отредактировано Dumby (24-02-2025 20:02:23)
Отсутствует
Не, это я, скорее, к тому, чтобы мне взять уже готовый код, а не сочинять самому.
Сочинение кода (точнее, выбор способа) изменения внешнего вида таблицы было отложено на самый-самый конец. Причина вот какая:
По команде открытия окна истории открывается history.xul, в котором элемент <tree> задан с жёстким перечнем столбцов. К history.xul через chrome.manifest прицеплен my.xul, стартовый код которого должен сделать что-то такое, от чего на экране будет <tree> с ещё одним дополнительным столбцом. Но ведь стартовый код history.xul уже отработал и история показана! И что, всю её удалять и выводить заново (как делает вчерашний код "красящий красным")? Не хочется.
А сделать что-либо с xul-ом до того, как окно открыто, невозможно. Значит, нужно или менять команду, открывающую окно истории, чтобы она сразу my.xul открывала, а в my.xul затащить всё содержимое history.xul (так себе решение), или заранее подменять методы класса, отвечающего за работу с этим <tree>.
Именно последнее и было выбрано. Но тогда сначала нужно научиться получать из БД нужные данные и засовывать их в <tree>, и только потом станет ясно - что, на что и как подменять.
Получать данные вчера научился. Начал думать, что с ними дальше делать - превращать в NavHistoryResult/NavHistoryContainerResultNode/NavHistoryResultNode для скармливания нынешнему PlacesTreeView, или делать custom tree view для работы непосредственно с тем, что возвращает SQL-запрос.
В результате обдумывания получил "двойной удар". Окно истории ведь "живое". Если оно открыто, а пользователь продолжает работать в браузере, то содержимое в окне истории меняется - появляются новые строки, у каких-то имеющихся меняется дата посещения, а у каких-то и имя страницы измениться может. А источником некоторых событий, приводящих к изменениям в окне, является сам объект результатов! Это он сообщает подключённому к нему PlacesTreeView, что что-то изменилось и нужно перевывести. А если у меня только результаты SQL-запроса, то после их получения я уже никак не узнаю, что в БД что-то поменялось. Что, ещё и своё слежение за БД организовывать? Количество кода, который надо добавлять в браузер становится несколько неприличным.
А если преобразовать результаты запроса в NavHistoryContainerResultNode, то от этого слежение за БД всё равно автоматически не появится.
В общем, пока что наиболее реалистичным представляется что-то в духе твоего вчерашнего кода - при выводе/обновлении очередной строки запрашивать, есть ли этот URL в закладках, и дальше (в зависимости от того, что покажется более удобным в пользовании) или менять визуальное представление имеющихся ячеек, или добавить столбец в таблицу, а при выводе/обновлении этой новой ячейки запрашивать isBookmarked и рисовать плюсик.
Некоторое уныние вызывает вот что: я в тот "красящий красным" код в функцию PTV_getCellProperties первой строкой вставил console.log('z'); после чего расположил окна так, что правая сторона консоли была видна из-под окна истории, и поводил мышкой над таблицей истории. Всего лишь поводил. Показания счётчика в строке консоли просто потрясли. И это же не "происки довеска", это родной мозилловский код так работает. Ну да деваться некуда.
Кстати, наткнулся на такое:
Обнаружился один урл, для которого foreign_count не совпадает с тем, что отдаёт TEST_XPCOM
В базе значение — три, а кодом без использования чтения базы — два.
Позавчера у меня было предположение, что foreign_count может быть счётчиком не только закладок. Но подозрение пало на записи истории адресной строки. Проверка показала, что нет, те записи на счётчик не влияют. А больше ничего в голову не пришло. Потому что всё остальное, как я считал, ссылается не на moz_places.
Оказалось, что добавление к закладке tag'а (метки) увеличивает foreign_count на единицу.
foreign_count, по логике названия, это счётчик внешних ссылок на строку таблицы из других таблиц. Но историю адресной строки я на это дело проверил - не влияет. Значит, только закладки. А сейчас полез проверять всё - и всё оказалось не так.
Видимо, PlacesUtils.bookmarks.getBookmarkIdsForURI() отдаёт результат без учёта папки меток.
А вот на Iceape — там для такой закладки совпадает, то есть метки учитываются.
В Seamonkey/Iceape закладка кроме URL и имени страницы может содержать метки(tags), краткое имя (keyword) и описание (description).
Описания сидят в отдельной таблице, но на foreign_count не влияют, так как ссылаются на таблицу закладок.
С короткими именами странно - они сидят в отдельной таблице (moz_keywords), индивидуальны для URL (и потому общие для всех закладок, созданных для этого URL) и на foreign_count, как я только что выяснил, влияют даже слишком сильно: если я несколько раз отредактирую текст, то все предыдущие варианты текста так в moz_keywords и останутся, и каждый будет ссылаться на одну и ту же запись в moz_places. При этом ни из moz_places, ни из moz_bookmarks на них ссылок нет, и по какому принципу выбирается, какой вариант показывать, непонятно. Самый последний, что ли?
В общем, у меня сейчас есть один URL в moz_places, три закладки для него в moz_bookmarks и пять записей в moz_keywords. На экране у всех трёх закладок keyword один и тот же, а foreign_count у URL-а - 8.
(Кстати, удалить keyword не удаётся. Редактировать - пожалуйста. Но если пытаюсь удалить полностью - восстанавливается. Всё, что смог - сократить до одной буквы. Наверное, какая-то ошибка в программе. Надо будет глянуть и исправить, если что.)
А с метками вообще чертовщина. Они тоже индивидуальны для URL (и, соответственно, общие для всех закладок, созданных для этого URL), и тоже на foreign_count влияют, но влияют правильно - ввожу у одной из тех трёх закладок, появляется во всех, а счётчик увеличивается на 1. Но при этом я вообще не нашёл, куда метки записываются. Их нет ни в одной таблице!
Да, точно, finalize()
А то я reset() как-то бездумно у тебя срисовал из предыдущего кода про sql_stmt.
Не принципиально. Просто вначале я выложил кусок от бОльшего кода, в котором тот фрагмент крутился в цикле, и там выгоднее было использовать reset().
А потом я те эксперименты закончил, цикл стал не нужен, я его удалил и reset() поменял на finalize().
Но поскольку это всё не для рабочего кода, а для "запустить, посмотреть результат, выбросить", то разницы особой нет.
Отсутствует
Кстати, удалить keyword не удаётся. Редактировать - пожалуйста.
Но если пытаюсь удалить полностью - восстанавливается. Всё, что смог - сократить до одной буквы.
Наверное, какая-то ошибка в программе. Надо будет глянуть и исправить, если что.
Да, я вижу это. Определённо баг. Вот попытка сочинить eval-патч.
Прямо в PlacesEditBookmarkKeywordTransaction (а не по окнам), исходя из предпосылки,
что он не должен допускать описанного тобой бага вообще как таковой.
Код должен исполняться только один раз.
Ну, то есть, из любого разумного окружения, где он будет исполняться только один раз.
Чтобы попробовать, можно запустить разок с консоли.
Понятное дело, что смотреть надо на урле, который не испорчен багом.
То есть, подопытный — урл без кейворда вообще, «и вперёд» после патча.
(repl => { var url = "resource://gre/modules/PlacesUtils.jsm"; var g = Components.utils.import(url, {}); var key = "doTransaction"; var proto = g.PlacesEditBookmarkKeywordTransaction.prototype; proto[key] = g.eval(`(${proto[key]})`.replace( " if (this.item.keyword) {", repl.trimRight() )); console.log("" + proto[key]); // Just log })(` // aOldKeyword may not be provided for unexpected reason. this.item.keyword ??= ( yield PlacesUtils.keywords.fetch({url: this.item.href}) )?.keyword;\n\n$& `);
не нашёл, куда метки записываются. Их нет ни в одной таблице!
У себя вижу так:
Создание новой метки образует в таблице moz_bookmarks запись,
представляющую папку (type == 2, надо полагать, папка).
В колонке title у этой папки — имя (текст) метки.
В колонке parent у этой папки, как и у всех других меток,
будет id'шник корневой папки Tags, той, у которой guid «tags________».
Помимо этого, в той же таблице, образуется запись,
представляющая закладку (type == 1, надо полагать, закладка).
В колонке parent у этой закладки будет id'шник
этой вышеупомянутой папки метки.
А в колонке fk — id'шник уже для другой таблицы, moz_places
в которой под этим id'шником запись с тем урлом, к которому прицеплена метка.
Если задаётся существующая метка,
то тоже самое, но без создания папки для метки.
Отредактировано Dumby (25-02-2025 17:16:58)
Отсутствует
Страницы: 1