1 # This file is part of the Enkel web programming library.
3 # Copyright (C) 2007 Espen Angell Kristiansen (espeak@users.sourceforge.net)
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 from datetime
import time
21 import sqlite3
as sqlite
23 from pysqlite2
import dbapi2
as sqlite
25 from enkel
.model
.field
.base
import Date
, DateTime
, Time
27 from std_adapter
import StdAdapter
29 from table
import Table
30 from query
import paramgen_qmark
31 from dbfields
import AutoincPk
, DbLong
, DbInt
35 """ Adapter to support datetime.date insertion on TIME cols. """
36 return t
.strftime("%H:%M:%S")
37 sqlite
.register_adapter(time
, adapt_time
)
40 class SqliteAdapter(StdAdapter
):
41 def __init__(self
, dbpath
):
44 self
.connection
= sqlite
.connect(dbpath
)
45 self
.connection
.isolation_level
= "DEFERRED"
46 self
.cursor
= self
.new_cursor()
48 def paramgen(self
, index
):
49 return paramgen_qmark(index
)
52 def execute(self
, query
, params
=None, cursor
=None):
53 cursor
= cursor
or self
.cursor
61 cursor
.execute(query
, params
)
64 except sqlite
.DataError
, e
:
65 raise DataError(str(e
))
66 except sqlite
.OperationalError
, e
:
67 raise OperationalError(str(e
))
68 except sqlite
.IntegrityError
, e
:
69 raise IntegrityError(str(e
))
70 except sqlite
.InternalError
, e
:
71 raise InternalError(str(e
))
72 except sqlite
.ProgrammingError
, e
:
73 raise ProgrammingError(str(e
))
76 def _get_sqltype(self
, fieldtype
, fieldname
, field
):
77 if isinstance(field
, DbInt
) or isinstance(field
, DbLong
):
80 super(SqliteAdapter
, self
)._get
_sqltype
(
81 fieldtype
, fieldname
, field
)
84 def _create_triggers(self
, table
):
85 """ Used by L{create_table} to create the required
86 foreign key triggers. """
87 table_name
= table
.name
88 for fieldname
, field
in table
.iter_fks():
89 ftable
= field
.datasource
90 ftable_pk
= ftable
.get_pk()
91 ftable_name
= ftable
.name
92 constraint
= "fk_%s" % fieldname
93 err
= 'on table "%(table_name)s" violates foreign key '\
94 'constraint on the "%(fieldname)s" field' % vars()
97 """CREATE TRIGGER fk%(act)s_%(table_name)s_%(fieldname)s
98 BEFORE %(ACT)s ON %(table_name)s
103 ) WHERE NEW.%(fieldname)s IS NOT NULL AND
104 (SELECT %(ftable_pk)s FROM %(ftable_name)s WHERE %(ftable_pk)s = NEW.%(fieldname)s) IS NULL;
109 self
.execute(qry
% vars())
113 self
.execute(qry
% vars())
116 """CREATE TRIGGER fkdel_%(table_name)s_%(fieldname)s
117 BEFORE DELETE ON %(ftable_name)s
121 'delete on table "%(ftable_name)s" violates foreign key constraint on the "%(table_name)s.%(fieldname)s" field'
122 ) WHERE (SELECT %(fieldname)s FROM %(table_name)s WHERE %(fieldname)s = OLD.%(ftable_pk)s) IS NOT NULL;
128 def _get_sqlfield(self
, fieldtype
, fieldname
, field
):
129 if fieldtype
== Table
.FT_FK
:
134 ftable
= field
.datasource
135 c
= "CONSTRAINT fk_%s REFERENCES %s(%s) ON DELETE CASCADE" % (
136 fieldname
, ftable
.name
, ftable
.get_pk())
137 d
= self
._get
_sqltype
(Table
.FT_NORM
, fieldname
,
138 field
.datasource
.field
)
139 return "%s %s%s\n\t\t%s" % (fieldname
, d
, n
, c
)
140 return super(SqliteAdapter
, self
)._get
_sqlfield
(
141 fieldtype
, fieldname
, field
)
143 def create_table(self
, table
):
145 for t
, fieldname
, field
in table
.iter_fields():
148 d
= self
._get
_sqlfield
(t
, fieldname
, field
)
150 cols
.append("PRIMARY KEY(%s)" % ",".join(table
.primary_keys
))
152 cols
.append("UNIQUE(%s)" % ",".join(table
.unique
))
153 qry
= "CREATE TABLE %s (\n\t%s\n);" % (table
.name
, ",\n\t".join(cols
))
155 self
._create
_triggers
(table
)
156 self
._create
_indexes
(table
)
159 def from_db(self
, field
, value
):
161 # use the base classes to ensure that subclasses cannot
162 # with different from_unicode cannot fuck things up
163 if isinstance(field
, Date
):
164 return Date
.from_unicode(field
, value
)
165 if isinstance(field
, DateTime
):
166 return DateTime
.from_unicode(field
, value
)
167 if isinstance(field
, Time
):
168 return Time
.from_unicode(field
, value
)