3 PRAGMA application_id = 0x5a504442;
4 PRAGMA user_version = 1;
6 -- should be faster with rowid due to the blob content
7 -- these are really just blobs of data
8 -- TODO copyright and license information should probably
11 hash text primary key, -- sha256 of content
12 size integer, -- bigint? certainly need > 2GB
13 compression text, -- always xz?
18 -- information about packages
19 -- a package is identified by a package,version,release triple
20 create table packages (
21 -- primary key columns
22 package text not null,
23 version text not null, -- the upstream version string
24 release integer not null, -- the local release number
25 -- pkgid text, -- the three above joined with '-'
32 licenses text, -- hash of actual license? need table for more than one?
34 build_time integer default (strftime('%s', 'now')),
36 hash text, -- see integ.c for package hash
37 primary key (package,version,release),
38 check (typeof(package) = 'text'),
39 check (typeof(version) = 'text'),
40 check (typeof(release) = 'integer'),
42 -- TODO enforce name and version conventions
43 -- check(instr(version,'-') = 0)
44 -- check(instr(package,'/') = 0)
45 -- check(instr(package,'/') = 0)
46 -- check(instr(version,' ') = 0)
47 -- check(instr(package,' ') = 0)
48 -- check(instr(package,' ') = 0)
49 -- check(length(package) < 64)
50 -- check(length(version) < 32)
55 create index package_status_index on packages (status);
56 create index package_package_index on packages (package);
58 create view packages_pkgid as
59 select printf('%s-%s-%s', package, version, release) as pkgid, *
62 create trigger packages_update_trigger instead of
63 update on packages_pkgid
66 set package = NEW.package,
67 version = NEW.version,
68 release = NEW.release,
69 description = NEW.description,
70 architecture = NEW.architecture,
73 licenses = NEW.licenses,
74 packager = NEW.packager,
75 build_time = NEW.build_time,
76 install_time = NEW.install_time,
78 where package = OLD.package
79 and version = OLD.version
80 and release = OLD.release
85 -- handle package status history with a logging trigger.
86 create trigger logpkgstatus after update of status on packages
87 begin insert into zpmlog (action,target,info)
88 values (printf('status change %s %s', OLD.status, NEW.status),
89 printf('%s-%s-%s', NEW.package, NEW.version, NEW.release),
92 create table packagetags (
98 set_time integer default (strftime('%s', 'now')),
99 primary key (package,version,release,tag),
100 foreign key (package,version,release) references packages (package,version,release) on delete cascade on update cascade
103 -- files contained in a package
104 create table packagefiles (
110 path text, -- filesystem path
111 mode text not null, -- perms, use text for octal rep?
112 username text not null, -- name of owner
113 groupname text not null, -- group of owner
114 uid integer, -- numeric uid, generally ignored
115 gid integer, -- numeric gid, generally ignored
116 configuration integer not null default 0, -- boolean if config file
117 filetype varchar not null default 'r',
121 -- h hard link -- not supported
122 -- c character special and b device special files add dev number column
124 -- p fifos (i.e. pipe)
125 target text, -- link target for links
126 -- device file dev numbers, should probably be a separate table
129 hash text, -- null if no actual content, i.e. anything but a regular file
130 mtime integer, -- seconds since epoch, finer resolution probably not needed
131 primary key (package,version,release,path),
132 foreign key (package,version,release) references packages (package,version,release) on delete cascade on update cascade,
133 check (not (filetype = 'l' and target is null)),
134 check (not (filetype = 'r' and hash is null)),
135 check (not (filetype = 'c' and (devmajor is null or devminor is null))),
136 check (not (filetype = 'b' and (devmajor is null or devminor is null))),
137 check (configuration = 0 or configuration = 1)
141 create index packagefile_package_index on packagefiles (package);
142 create index packagefile_path_index on packagefiles (path);
143 create index packagefile_hash_index on packagefiles (hash);
145 create view packagefiles_pkgid as
146 select printf('%s-%s-%s', package, version, release) as pkgid, *,
147 printf('%s:%o:%s:%s', filetype, mode, username, groupname) as mds
151 create trigger packagefiles_update_trigger instead of
152 update on packagefiles_pkgid
155 set package = NEW.package,
156 version = NEW.version,
157 release = NEW.release,
160 username = NEW.username,
161 groupname = NEW.groupname,
164 configuration = NEW.configuration,
165 filetype = NEW.filetype,
167 devmajor = NEW.devmajor,
168 devminor = NEW.devminor,
171 where package = OLD.package
172 and version = OLD.version
173 and release = OLD.release
179 create view installed_ref_count as
180 select I.path, count(*) as refcount
181 from installedfiles I
185 create view sync_status_ref_count as
186 select path, status, count(*) as refcount
187 from packagefiles_status
188 where status in ('installed', 'installing', 'removing')
189 group by path, status
192 create view packagefiles_status as
193 select P.status, PF.*
194 from packagefiles_pkgid PF
195 left join packages_pkgid P on P.pkgid = PF.pkgid
198 create view installedfiles as
199 select * from packagefiles_status
200 where status = 'installed'
203 create view install_status as
205 select 'new' as op, PN.*
206 from packagefiles_status PN
207 left join installed_ref_count RC on RC.path = PN.path
208 where RC.refcount is null
209 and PN.status = 'installing'
213 select 'update' as op, PN.*
214 from packagefiles_status PN
215 inner join installedfiles PI on PI.path = PN.path and PI.package = PN.package
216 left join installed_ref_count RC on RC.path = PN.path
217 where RC.refcount = 1
218 and PN.status = 'installing'
219 and PI.hash is not PN.hash
223 select 'conflict' as op, PI.*
224 from packagefiles_status PN
225 inner join installedfiles PI on PI.path = PN.path and PI.package != PN.package
226 where PN.status = 'installing'
229 select 'remove' as op, PI.*
230 from installedfiles PI
231 left join packagefiles_status PN
232 on PI.path = PN.path and PI.package = PN.package
233 and PI.pkgid != PN.pkgid
234 where PN.path is null
235 and PI.package in (select package from packages where status = 'installing')
238 -- remove files in removing, but not installing
239 select distinct 'remove' as op, PR.*
240 from packagefiles_status PR
241 left join packagefiles_status PN
243 and PR.pkgid != PN.pkgid and PN.status in ('installing', 'installed')
244 where PN.path is null
245 and PR.status = 'removing'
248 create table pathtags (
254 path text, -- filesystem path
256 primary key (package,version,release,path,tag),
257 foreign key (package,version,release,path)
258 references packagefiles on delete cascade on update cascade
263 create view elfdeps as
264 select PF.pkgid, PF.status, PF.path, N.needed as needs,
265 PL.path as library, PL.pkgid provider, PL.status as library_status
266 from packagefiles_status PF
267 join elfneeded N on N.file = PF.hash
268 left join elflibraries L on N.needed = L.soname
269 left join packagefiles_status PL on PL.hash = L.file
272 -- TODO just elf information?
273 -- and just hash, not package?
274 create table elflibraries (
275 file text primary key,
281 create table elfneeded (
283 needed text, -- soname of dependency
284 primary key (file, needed)
289 -- package scripts: table of package, stage, file
290 create table scripts (
296 primary key (package,version,release,stage),
297 foreign key (package,version,release) references packages (package,version,release) on delete cascade on update cascade
300 create view scripts_pkgid as
301 select printf('%s-%s-%s', package, version, release) as pkgid, *
305 -- package dependencies: table of package, dependency, dep type (package, soname)
306 create table packagedeps (
310 requires text, -- package name (only)
313 primary key (package,version,release,package),
314 foreign key (package,version,release) references packages (package,version,release) on delete cascade on update cascade
318 create table provides (
321 label text -- a capability label
324 create table requires (
327 label text -- a capability label
330 create table packagegroups (
336 -- not sure how machine readable this needs to be,
337 -- do not at all for now, figure it out later
338 -- could be worth logging all commands in a history table,
339 -- the zpm driver could do that and capture the exit status
341 -- might want the history table to note a "group" to tie together
342 -- sub-invocations, probably an environment variable set if not
343 -- already set by zpm, probably a uuid or a timestamp
344 create table zpmlog (
345 ts text default (strftime('%Y-%m-%d %H:%M:%f', 'now')),
346 -- timestamp of action
348 target text, -- packagename, repo name, etc
349 info text -- human readable
352 create table history (
353 ts integer, -- again, probably needs timestamp sub second
359 create table repository (
360 name text primary key, -- our name for a repo
362 priority integer not null default 1,
363 refreshed integer -- last refresh time
366 -- urls for downloading packages. possibly unneeded
367 create table repository_packages (
369 pkg text, -- glob pattern? in which case others not needed
375 -- track which repository a package was cloned from, i.e. where we got it
376 create table packagesource (
380 repository text references repository
383 create view syncconflicts as
386 select BASE.*, 'preserved' as rstatus
387 from packagefiles_status BASE
388 join elflibraries EL on EL.file = BASE.hash
390 BASE.status in ('removed', 'updated')
391 and BASE.hash in (select hash from packagefiles_status where
392 status in ('installed'))
395 select distinct BASE.*,
396 case when P.status = 'installing' and BASE.status = 'installed'
398 when BASE.status in ('removed','updated')
399 and BASE.path in (select path from preserved) then
404 from packagefiles_status BASE
405 left join packages P on P.package = BASE.package
406 and BASE.status in ('installed', 'removing')
407 and P.status = 'installing'
409 -- metadata different
411 select path, count(distinct mds) as mdcount,
412 count(distinct hash) as hashcount
414 where SS.rstatus in ('installing', 'installed')
416 having (count(distinct mds) > 1 or count(distinct hash) > 1)
418 select BASE.*, 'hash' as conflict
420 where path in (select path from md_conflict where hashcount > 1)
422 select BASE.*, 'md' as conflict
424 where path in (select path from md_conflict where mdcount > 1)
427 create view syncinfo as
430 select BASE.*, 'preserved' as rstatus
431 from packagefiles_status BASE
432 join elflibraries EL on EL.file = BASE.hash
434 BASE.status in ('removed', 'updated')
435 and BASE.hash in (select hash from packagefiles_status where
436 status in ('installed'))
439 select distinct BASE.*,
440 case when P.status = 'installing' and BASE.status = 'installed'
442 when BASE.status in ('removed','updated')
443 and BASE.path in (select path from preserved) then
448 from packagefiles_status BASE
449 left join packages P on P.package = BASE.package
450 and BASE.status in ('installed', 'removing')
451 and P.status = 'installing'
453 -- new file: in installing, not in installed or updating or removing
456 path,username,uid,groupname,gid,mode,filetype,mtime,hash,
457 target,devminor,devmajor
459 where path not in (select path from syncstatus where
460 rstatus in ('installed', 'updating', 'removing')
462 and rstatus in ('installing')
464 -- modified: retained, but with different metadata
469 SS.uid, SS.groupname, SS.gid, SS.mode,
470 SS.filetype, SS.mtime, SS.hash, SS.target, SS.devminor, SS.devmajor
473 on SS.path = OS.path and SS.pkgid is not OS.pkgid
475 and OS.rstatus in ('installed','updating','removing')
476 and (SS.mds is not OS.mds or SS.hash is not OS.hash)
478 SS.rstatus in ('installing')
480 -- preserve: libraries needed by something in installed or installing
485 where status in ('installed', 'installing')
486 and library is not null
490 path,username,uid,groupname,gid,mode,filetype,mtime,hash,
491 target,devminor,devmajor
493 where path in (select library from needed)
494 and SS.rstatus in ('removing', 'removed')
496 -- remove: cur, not preserved, not in final set
499 path,username,uid,groupname,gid,mode,filetype,mtime,hash,
500 target,devminor,devmajor
503 select path from syncstatus where
504 rstatus in ('installed', 'installing')
506 and path not in (select path from preserve)
507 and rstatus in ('removing', 'updating')
509 -- expired: libraries that had been preserved, but aren't needed now
512 path,username,uid,groupname,gid,mode,filetype,mtime,hash,
513 target,devminor,devmajor
515 where hash in (select file from elflibraries where file is not null)
516 and path not in (select path from preserve)
517 and rstatus in ('removed','updated')
519 select 'update' as op, * from modified
521 select 'remove' as op, * from remove
523 select 'obsolete' as op, * from expired
525 select 'new' as op, * from newfiles
527 select 'preserve' as op, * from preserve