1 | from ..adapters.oracle import Oracle |
---|
2 | from .._compat import integer_types, basestring |
---|
3 | from .base import SQLDialect |
---|
4 | from . import dialects, sqltype_for |
---|
5 | import re |
---|
6 | |
---|
7 | |
---|
8 | @dialects.register_for(Oracle) |
---|
9 | class OracleDialect(SQLDialect): |
---|
10 | false_exp = "1=0" |
---|
11 | true_exp = "1=1" |
---|
12 | |
---|
13 | @sqltype_for("string") |
---|
14 | def type_string(self): |
---|
15 | return "VARCHAR2(%(length)s)" |
---|
16 | |
---|
17 | @sqltype_for("text") |
---|
18 | def type_text(self): |
---|
19 | return "CLOB" |
---|
20 | |
---|
21 | @sqltype_for("integer") |
---|
22 | def type_integer(self): |
---|
23 | return "INT" |
---|
24 | |
---|
25 | @sqltype_for("bigint") |
---|
26 | def type_bigint(self): |
---|
27 | return "NUMBER" |
---|
28 | |
---|
29 | @sqltype_for("double") |
---|
30 | def type_double(self): |
---|
31 | return "BINARY_DOUBLE" |
---|
32 | |
---|
33 | @sqltype_for("time") |
---|
34 | def type_time(self): |
---|
35 | return "TIME(8)" |
---|
36 | |
---|
37 | @sqltype_for("datetime") |
---|
38 | def type_datetime(self): |
---|
39 | return "DATE" |
---|
40 | |
---|
41 | @sqltype_for("id") |
---|
42 | def type_id(self): |
---|
43 | return "NUMBER PRIMARY KEY" |
---|
44 | |
---|
45 | @sqltype_for("reference") |
---|
46 | def type_reference(self): |
---|
47 | return ( |
---|
48 | "NUMBER, CONSTRAINT %(constraint_name)s FOREIGN KEY " |
---|
49 | + "(%(field_name)s) REFERENCES %(foreign_key)s ON DELETE " |
---|
50 | + "%(on_delete_action)s" |
---|
51 | ) |
---|
52 | |
---|
53 | @sqltype_for("reference FK") |
---|
54 | def type_reference_fk(self): |
---|
55 | return ( |
---|
56 | ", CONSTRAINT FK_%(constraint_name)s FOREIGN KEY " |
---|
57 | + "(%(field_name)s) REFERENCES %(foreign_key)s " |
---|
58 | + "ON DELETE %(on_delete_action)s" |
---|
59 | ) |
---|
60 | |
---|
61 | @sqltype_for("reference TFK") |
---|
62 | def type_reference_tfk(self): |
---|
63 | return ( |
---|
64 | " CONSTRAINT FK_%(constraint_name)s_PK FOREIGN KEY " |
---|
65 | + "(%(field_name)s) REFERENCES %(foreign_table)s" |
---|
66 | + "(%(foreign_key)s) ON DELETE %(on_delete_action)s" |
---|
67 | ) |
---|
68 | |
---|
69 | def left_join(self, val, query_env={}): |
---|
70 | if not isinstance(val, basestring): |
---|
71 | val = self.expand(val, query_env=query_env) |
---|
72 | return "LEFT OUTER JOIN %s" % val |
---|
73 | |
---|
74 | @property |
---|
75 | def random(self): |
---|
76 | return "dbms_random.value" |
---|
77 | |
---|
78 | def cast(self, first, second, query_env={}): |
---|
79 | if second == "CLOB": |
---|
80 | return "TO_CHAR(%s)" % self.expand(first, query_env=query_env) |
---|
81 | return "CAST(%s)" % self._as(first, second, query_env) |
---|
82 | |
---|
83 | def mod(self, first, second, query_env={}): |
---|
84 | return "MOD(%s,%s)" % ( |
---|
85 | self.expand(first, query_env=query_env), |
---|
86 | self.expand(second, first.type, query_env=query_env), |
---|
87 | ) |
---|
88 | |
---|
89 | def extract(self, first, what, query_env={}): |
---|
90 | if what == "hour": |
---|
91 | return "TO_CHAR(%s, 'HH24')" % self.expand(first, query_env=query_env) |
---|
92 | if what == "minute": |
---|
93 | return "TO_CHAR(%s, 'MI')" % self.expand(first, query_env=query_env) |
---|
94 | if what == "second": |
---|
95 | return "TO_CHAR(%s, 'SS')" % self.expand(first, query_env=query_env) |
---|
96 | return "EXTRACT(%s FROM %s)" % (what, self.expand(first, query_env=query_env)) |
---|
97 | |
---|
98 | def epoch(self, val, query_env={}): |
---|
99 | return "(%s - DATE '1970-01-01')*24*60*60" % self.expand( |
---|
100 | val, query_env=query_env |
---|
101 | ) |
---|
102 | |
---|
103 | def quote(self, val): |
---|
104 | if not (val[0] == '"' and val[-1] == '"'): |
---|
105 | return self.quote_template % val |
---|
106 | return val |
---|
107 | |
---|
108 | def _as(self, first, second, query_env={}): |
---|
109 | return "%s %s" % (self.expand(first, query_env), self.quote(second)) |
---|
110 | |
---|
111 | def alias(self, original, new): |
---|
112 | return "%s %s" % (original, self.quote(new)) |
---|
113 | |
---|
114 | def writing_alias(self, table): |
---|
115 | return self.sql_fullref(table) |
---|
116 | |
---|
117 | def sqlsafe(self, field): |
---|
118 | if field._table is None: |
---|
119 | raise SyntaxError("Field %s is not bound to any table" % field.name) |
---|
120 | return self.quote(field._table.sql_shortref) + "." + self.quote(field._rname) |
---|
121 | |
---|
122 | def longname(self, field): |
---|
123 | if field._table is None: |
---|
124 | raise SyntaxError("Field %s is not bound to any table" % field.name) |
---|
125 | return self.quote(field._table._tablename) + "." + self.quote(field.name) |
---|
126 | |
---|
127 | def sql_fullref(self, table): |
---|
128 | if table._tablename == table._dalname: |
---|
129 | return self.quote(table._rname) |
---|
130 | return self.adapter.sqlsafe_table(table._tablename, table._rname) |
---|
131 | |
---|
132 | def trigger_name(self, tablename): |
---|
133 | return "%s_trigger" % tablename |
---|
134 | |
---|
135 | def sequence_name(self, tablename): |
---|
136 | if tablename[0] == '"': |
---|
137 | # manually written quotes, typically in case-sensitive rname |
---|
138 | tablename = tablename[1:-1] |
---|
139 | # truncate to max length |
---|
140 | return self.quote(("%s_sequence" % tablename)[0:29]) |
---|
141 | |
---|
142 | def constraint_name(self, table, fieldname): |
---|
143 | if table[0] == '"': |
---|
144 | # manually written quotes, typically in case-sensitive rname |
---|
145 | table = table[1:-1] |
---|
146 | constraint_name = super(OracleDialect, self).constraint_name(table, fieldname) |
---|
147 | if len(constraint_name) > 30: |
---|
148 | constraint_name = "%s_%s__constraint" % (table[:10], fieldname[:7]) |
---|
149 | return constraint_name |
---|
150 | |
---|
151 | def primary_key(self, key): |
---|
152 | if len(re.split(",\s*", key)) > 1: |
---|
153 | return "PRIMARY KEY(%s)" % ", ".join( |
---|
154 | [self.quote(k) for k in re.split(",\s*", key)] |
---|
155 | ) |
---|
156 | return "PRIMARY KEY(%s)" % key |
---|
157 | |
---|
158 | def not_null(self, default, field_type): |
---|
159 | return "DEFAULT %s NOT NULL" % self.adapter.represent(default, field_type) |
---|
160 | |
---|
161 | def not_null(self, default, field_type): |
---|
162 | return "NOT NULL DEFAULT %s" % self.adapter.represent(default, field_type) |
---|
163 | |
---|
164 | def eq(self, first, second=None, query_env={}): |
---|
165 | if (first.type == "text" or first.type[:4] == "list") and second: |
---|
166 | return "(TO_CHAR(%s) = %s)" % ( |
---|
167 | self.expand(first, query_env=query_env), |
---|
168 | self.expand(second, first.type, query_env=query_env), |
---|
169 | ) |
---|
170 | return super(OracleDialect, self).eq(first, second, query_env) |
---|
171 | |
---|
172 | def regexp(self, first, second, query_env={}): |
---|
173 | return "REGEXP_LIKE(%s, %s)" % ( |
---|
174 | self.expand(first, query_env=query_env), |
---|
175 | self.expand(second, "string", query_env=query_env), |
---|
176 | ) |
---|
177 | |
---|
178 | def insert(self, table, fields, values): |
---|
179 | return "INSERT INTO %s(%s) VALUES (%s);" % (self.quote(table), fields, values) |
---|
180 | |
---|
181 | def insert_empty(self, table): |
---|
182 | return "INSERT INTO %s VALUES (DEFAULT);" % table |
---|
183 | |
---|
184 | def _select_aux(self, sql, fields, attributes, colnames): |
---|
185 | return super._select_aux(sql, fields, attributes, colnames) |
---|
186 | |
---|
187 | def select( |
---|
188 | self, |
---|
189 | fields, |
---|
190 | tables, |
---|
191 | where=None, |
---|
192 | groupby=None, |
---|
193 | having=None, |
---|
194 | orderby=None, |
---|
195 | limitby=None, |
---|
196 | distinct=False, |
---|
197 | for_update=False, |
---|
198 | ): |
---|
199 | dst, whr, grp, order, limit, offset, upd = "", "", "", "", "", "", "" |
---|
200 | if distinct is True: |
---|
201 | dst = " DISTINCT" |
---|
202 | elif distinct: |
---|
203 | dst = " DISTINCT ON (%s)" % distinct |
---|
204 | if where: |
---|
205 | whr = " %s" % self.where(where) |
---|
206 | if groupby: |
---|
207 | grp = " GROUP BY %s" % groupby |
---|
208 | if having: |
---|
209 | grp += " HAVING %s" % having |
---|
210 | if orderby: |
---|
211 | order = " ORDER BY %s" % orderby |
---|
212 | if limitby: |
---|
213 | (lmin, lmax) = limitby |
---|
214 | if whr: |
---|
215 | whr2 = whr + " AND w_row > %i" % lmin |
---|
216 | else: |
---|
217 | whr2 = self.where("w_row > %i" % lmin) |
---|
218 | return """ |
---|
219 | SELECT%s * FROM ( |
---|
220 | SELECT w_tmp.*, ROWNUM w_row FROM ( |
---|
221 | SELECT %s FROM %s%s%s%s |
---|
222 | ) w_tmp |
---|
223 | ) WHERE w_row<=%i and w_row>%i |
---|
224 | """ % ( |
---|
225 | dst, |
---|
226 | fields, |
---|
227 | tables, |
---|
228 | whr, |
---|
229 | grp, |
---|
230 | order, |
---|
231 | lmax, |
---|
232 | lmin, |
---|
233 | ) |
---|
234 | if for_update: |
---|
235 | upd = " FOR UPDATE" |
---|
236 | return "SELECT%s %s FROM %s%s%s%s%s%s%s;" % ( |
---|
237 | dst, |
---|
238 | fields, |
---|
239 | tables, |
---|
240 | whr, |
---|
241 | grp, |
---|
242 | order, |
---|
243 | limit, |
---|
244 | offset, |
---|
245 | upd, |
---|
246 | ) |
---|
247 | |
---|
248 | def drop_table(self, table, mode): |
---|
249 | sequence_name = table._sequence_name |
---|
250 | if mode and mode.upper() == "CASCADE": |
---|
251 | mode = "CASCADE CONSTRAINTS" |
---|
252 | drops = [ |
---|
253 | "DROP TABLE %s %s;" % (self.quote(table._rname), mode), |
---|
254 | ] |
---|
255 | if "_id" in table: |
---|
256 | drops.append("DROP SEQUENCE %s;" % sequence_name) |
---|
257 | return drops |
---|