merge from upstream

This commit is contained in:
Michele Comitini
2012-10-03 22:46:34 +02:00
12 changed files with 105 additions and 53 deletions
+1 -1
View File
@@ -1 +1 @@
Version 2.0.9 (2012-10-01 15:54:19) dev Version 2.0.9 (2012-10-03 12:32:01) dev
@@ -207,6 +207,7 @@ def select():
if match: if match:
table = match.group('table') table = match.group('table')
try: try:
tb = None
nrows = db(query).count() nrows = db(query).count()
if form.vars.update_check and form.vars.update_fields: if form.vars.update_check and form.vars.update_fields:
db(query).update(**eval_in_global_env('dict(%s)' db(query).update(**eval_in_global_env('dict(%s)'
@@ -221,6 +222,8 @@ def select():
else: else:
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop)) rows = db(query,ignore_common_filters=True).select(limitby=(start, stop))
except Exception, e: except Exception, e:
import traceback
tb = traceback.format_exc()
(rows, nrows) = ([], 0) (rows, nrows) = ([], 0)
response.flash = DIV(T('Invalid Query'),PRE(str(e))) response.flash = DIV(T('Invalid Query'),PRE(str(e)))
# begin handle upload csv # begin handle upload csv
@@ -250,6 +253,7 @@ def select():
rows=rows, rows=rows,
query=request.vars.query, query=request.vars.query,
formcsv = formcsv, formcsv = formcsv,
tb = tb,
) )
+6
View File
@@ -44,6 +44,12 @@
{{elif request.function=='select':}} {{elif request.function=='select':}}
<h2>{{=XML(str(T("Database %s select"))%A(request.args[0],_href=URL('index'))) }} <h2>{{=XML(str(T("Database %s select"))%A(request.args[0],_href=URL('index'))) }}
</h2> </h2>
{{if tb:}}
<h3>{{=T('Traceback')}}</h3>
<pre>
{{=tb}}
</pre>
{{pass}}
{{if table:}} {{if table:}}
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/> {{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/>
<h3>{{=T("Rows in Table")}}</h3><br/> <h3>{{=T("Rows in Table")}}</h3><br/>
@@ -207,6 +207,7 @@ def select():
if match: if match:
table = match.group('table') table = match.group('table')
try: try:
tb = None
nrows = db(query).count() nrows = db(query).count()
if form.vars.update_check and form.vars.update_fields: if form.vars.update_check and form.vars.update_fields:
db(query).update(**eval_in_global_env('dict(%s)' db(query).update(**eval_in_global_env('dict(%s)'
@@ -221,6 +222,8 @@ def select():
else: else:
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop)) rows = db(query,ignore_common_filters=True).select(limitby=(start, stop))
except Exception, e: except Exception, e:
import traceback
tb = traceback.format_exc()
(rows, nrows) = ([], 0) (rows, nrows) = ([], 0)
response.flash = DIV(T('Invalid Query'),PRE(str(e))) response.flash = DIV(T('Invalid Query'),PRE(str(e)))
# begin handle upload csv # begin handle upload csv
@@ -250,6 +253,7 @@ def select():
rows=rows, rows=rows,
query=request.vars.query, query=request.vars.query,
formcsv = formcsv, formcsv = formcsv,
tb = tb,
) )
@@ -44,6 +44,12 @@
{{elif request.function=='select':}} {{elif request.function=='select':}}
<h2>{{=XML(str(T("Database %s select"))%A(request.args[0],_href=URL('index'))) }} <h2>{{=XML(str(T("Database %s select"))%A(request.args[0],_href=URL('index'))) }}
</h2> </h2>
{{if tb:}}
<h3>{{=T('Traceback')}}</h3>
<pre>
{{=tb}}
</pre>
{{pass}}
{{if table:}} {{if table:}}
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/> {{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/>
<h3>{{=T("Rows in Table")}}</h3><br/> <h3>{{=T("Rows in Table")}}</h3><br/>
@@ -207,6 +207,7 @@ def select():
if match: if match:
table = match.group('table') table = match.group('table')
try: try:
tb = None
nrows = db(query).count() nrows = db(query).count()
if form.vars.update_check and form.vars.update_fields: if form.vars.update_check and form.vars.update_fields:
db(query).update(**eval_in_global_env('dict(%s)' db(query).update(**eval_in_global_env('dict(%s)'
@@ -221,6 +222,8 @@ def select():
else: else:
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop)) rows = db(query,ignore_common_filters=True).select(limitby=(start, stop))
except Exception, e: except Exception, e:
import traceback
tb = traceback.format_exc()
(rows, nrows) = ([], 0) (rows, nrows) = ([], 0)
response.flash = DIV(T('Invalid Query'),PRE(str(e))) response.flash = DIV(T('Invalid Query'),PRE(str(e)))
# begin handle upload csv # begin handle upload csv
@@ -250,6 +253,7 @@ def select():
rows=rows, rows=rows,
query=request.vars.query, query=request.vars.query,
formcsv = formcsv, formcsv = formcsv,
tb = tb,
) )
+6
View File
@@ -44,6 +44,12 @@
{{elif request.function=='select':}} {{elif request.function=='select':}}
<h2>{{=XML(str(T("Database %s select"))%A(request.args[0],_href=URL('index'))) }} <h2>{{=XML(str(T("Database %s select"))%A(request.args[0],_href=URL('index'))) }}
</h2> </h2>
{{if tb:}}
<h3>{{=T('Traceback')}}</h3>
<pre>
{{=tb}}
</pre>
{{pass}}
{{if table:}} {{if table:}}
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/> {{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/>
<h3>{{=T("Rows in Table")}}</h3><br/> <h3>{{=T("Rows in Table")}}</h3><br/>
+38 -22
View File
@@ -594,7 +594,9 @@ class BaseAdapter(ConnectionPool):
support_distributed_transaction = False support_distributed_transaction = False
uploads_in_blob = False uploads_in_blob = False
can_select_for_update = True can_select_for_update = True
TRUE = 'T'
FALSE = 'F'
types = { types = {
'boolean': 'CHAR(1)', 'boolean': 'CHAR(1)',
'string': 'CHAR(%(length)s)', 'string': 'CHAR(%(length)s)',
@@ -620,9 +622,17 @@ class BaseAdapter(ConnectionPool):
'big-reference': 'BIGINT REFERENCES %(foreign_key)s ON DELETE %(on_delete_action)s', 'big-reference': 'BIGINT REFERENCES %(foreign_key)s ON DELETE %(on_delete_action)s',
} }
def id_query(self, table):
return table._id != None
def adapt(self, obj): def adapt(self, obj):
return "'%s'" % obj.replace("'", "''") return "'%s'" % obj.replace("'", "''")
def smart_adapt(self, obj):
if isinstance(obj,(int,float)):
return str(obj)
return self.adapt(str(obj))
def integrity_error(self): def integrity_error(self):
return self.driver.IntegrityError return self.driver.IntegrityError
@@ -1703,10 +1713,10 @@ class BaseAdapter(ConnectionPool):
if not r is None: if not r is None:
return r return r
if fieldtype == 'boolean': if fieldtype == 'boolean':
if obj and not str(obj)[:1].upper() in ['F', '0']: if obj and not str(obj)[:1].upper() in '0F':
return "'T'" return self.smart_adapt(self.TRUE)
else: else:
return "'F'" return self.smart_adapt(self.FALSE)
if fieldtype == 'id' or fieldtype == 'integer': if fieldtype == 'id' or fieldtype == 'integer':
return str(int(obj)) return str(int(obj))
if field_is_type('decimal'): if field_is_type('decimal'):
@@ -2946,13 +2956,8 @@ class MSSQLAdapter(BaseAdapter):
sql_s += ' TOP %i' % lmax sql_s += ' TOP %i' % lmax
return 'SELECT %s %s FROM %s%s%s;' % (sql_s, sql_f, sql_t, sql_w, sql_o) return 'SELECT %s %s FROM %s%s%s;' % (sql_s, sql_f, sql_t, sql_w, sql_o)
def represent_exceptions(self, obj, fieldtype): TRUE = 1
if fieldtype == 'boolean': FALSE = 0
if obj and not str(obj)[0].upper() == 'F':
return '1'
else:
return '0'
return None
REGEX_DSN = re.compile('^(?P<dsn>.+)$') REGEX_DSN = re.compile('^(?P<dsn>.+)$')
REGEX_URI = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>[^\?]+)(\?(?P<urlargs>.*))?$') REGEX_URI = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>[^\?]+)(\?(?P<urlargs>.*))?$')
@@ -3262,7 +3267,9 @@ class FireBirdAdapter(BaseAdapter):
return 'SUBSTRING(%s from %s for %s)' % (self.expand(field), parameters[0], parameters[1]) return 'SUBSTRING(%s from %s for %s)' % (self.expand(field), parameters[0], parameters[1])
def CONTAINS(self, first, second): def CONTAINS(self, first, second):
if first.type.startswith('list:'): if first.type in ('string','text'):
key = str(second).replace('%','%%')
elif first.type.startswith('list:'):
key = '|'+str(second).replace('|','||').replace('%','%%')+'|' key = '|'+str(second).replace('|','||').replace('%','%%')+'|'
return '(%s CONTAINING %s)' % (self.expand(first), return '(%s CONTAINING %s)' % (self.expand(first),
self.expand(key,'string')) self.expand(key,'string'))
@@ -4056,6 +4063,9 @@ class NoSQLAdapter(BaseAdapter):
return unicode(obj) return unicode(obj)
return obj return obj
def id_query(self, table):
return table._id > 0
def represent(self, obj, fieldtype): def represent(self, obj, fieldtype):
field_is_type = fieldtype.startswith field_is_type = fieldtype.startswith
if isinstance(obj, CALLABLETYPES): if isinstance(obj, CALLABLETYPES):
@@ -4089,7 +4099,7 @@ class NoSQLAdapter(BaseAdapter):
obj = obj['id'] obj = obj['id']
obj = long(obj) obj = long(obj)
elif fieldtype == 'boolean': elif fieldtype == 'boolean':
if obj and not str(obj)[0].upper() == 'F': if obj and not str(obj)[0].upper() in '0F':
obj = True obj = True
else: else:
obj = False obj = False
@@ -4406,7 +4416,7 @@ class GoogleDatastoreAdapter(NoSQLAdapter):
return self.expand(first) return self.expand(first)
def truncate(self,table,mode): def truncate(self,table,mode):
self.db(table._id > 0).delete() self.db(table._id).delete()
def select_raw(self,query,fields=None,attributes=None): def select_raw(self,query,fields=None,attributes=None):
db = self.db db = self.db
@@ -4424,7 +4434,7 @@ class GoogleDatastoreAdapter(NoSQLAdapter):
tablename = self.get_table(query) tablename = self.get_table(query)
elif fields: elif fields:
tablename = fields[0].tablename tablename = fields[0].tablename
query = fields[0].table._id != None query = db._adapter.id_query(fields[0].table)
else: else:
raise SyntaxError, "Unable to determine a tablename" raise SyntaxError, "Unable to determine a tablename"
@@ -6571,7 +6581,10 @@ class DAL(object):
Field('fieldname2')) Field('fieldname2'))
""" """
def __new__(cls, uri='sqlite://dummy.db', *args, **kwargs): def __new__(cls, uri='sqlite://dummy.db', *args, **kwargs):
if uri==None and not 'singleton_code' in kwargs:
# this deal with the special case of Dummy DAL for SQLFORM.factory
return super(DAL, cls).__new__(cls, uri, *args, **kwargs)
if not hasattr(THREAD_LOCAL,'db_instances'): if not hasattr(THREAD_LOCAL,'db_instances'):
THREAD_LOCAL.db_instances = {} THREAD_LOCAL.db_instances = {}
if 'singleton_code' in kwargs: if 'singleton_code' in kwargs:
@@ -7119,7 +7132,7 @@ def index():
def __call__(self, query=None, ignore_common_filters=None): def __call__(self, query=None, ignore_common_filters=None):
if isinstance(query,Table): if isinstance(query,Table):
query = query._id != None query = self._adapter.id_query(query)
elif isinstance(query,Field): elif isinstance(query,Field):
query = query!=None query = query!=None
return Set(self, query, ignore_common_filters=ignore_common_filters) return Set(self, query, ignore_common_filters=ignore_common_filters)
@@ -7236,7 +7249,7 @@ def index():
kwargs.get("write_colnames", True) kwargs.get("write_colnames", True)
for table in self.tables: for table in self.tables:
ofile.write('TABLE %s\r\n' % table) ofile.write('TABLE %s\r\n' % table)
query = self[table]._id > 0 query = self._adapter.id_query(self[table])
nrows = self(query).count() nrows = self(query).count()
kwargs['write_colnames'] = write_colnames kwargs['write_colnames'] = write_colnames
for k in range(0,nrows,step): for k in range(0,nrows,step):
@@ -7860,8 +7873,11 @@ class Table(object):
value = bar_decode_string(value) value = bar_decode_string(value)
elif field.type.startswith(list_reference_s): elif field.type.startswith(list_reference_s):
ref_table = field.type[len(list_reference_s):].strip() ref_table = field.type[len(list_reference_s):].strip()
value = [id_map[ref_table][int(v)] \ if id_map is not None:
value = [id_map[ref_table][int(v)] \
for v in bar_decode_string(value)] for v in bar_decode_string(value)]
else:
value = [v for v in bar_decode_string(value)]
elif field.type.startswith('list:'): elif field.type.startswith('list:'):
value = bar_decode_integer(value) value = bar_decode_integer(value)
elif id_map and field.type.startswith('reference'): elif id_map and field.type.startswith('reference'):
@@ -8666,7 +8682,7 @@ class Set(object):
def __call__(self, query, ignore_common_filters=False): def __call__(self, query, ignore_common_filters=False):
if isinstance(query,Table): if isinstance(query,Table):
query = query._id != None query = self.db._adapter.id_query(query)
elif isinstance(query,str): elif isinstance(query,str):
query = Expression(self.db,query) query = Expression(self.db,query)
elif isinstance(query,Field): elif isinstance(query,Field):
@@ -9444,10 +9460,10 @@ def test_all():
Example of expressions Example of expressions
>>> mynumber = db.define_table('mynumber', Field('x', 'integer')) >>> mynumber = db.define_table('mynumber', Field('x', 'integer'))
>>> db(mynumber.id>0).delete() >>> db(mynumber).delete()
0 0
>>> for i in range(10): tmp = mynumber.insert(x=i) >>> for i in range(10): tmp = mynumber.insert(x=i)
>>> db(mynumber.id>0).select(mynumber.x.sum())[0](mynumber.x.sum()) >>> db(mynumber).select(mynumber.x.sum())[0](mynumber.x.sum())
45 45
>>> db(mynumber.x+2==5).select(mynumber.x + 2)[0](mynumber.x + 2) >>> db(mynumber.x+2==5).select(mynumber.x + 2)[0](mynumber.x + 2)
+3 -1
View File
@@ -128,6 +128,7 @@ class Request(Storage):
and secure the session. and secure the session.
""" """
if not global_settings.cronjob and not self.is_https: if not global_settings.cronjob and not self.is_https:
session.forget()
redirect(URL(scheme='https', args=self.args, vars=self.vars)) redirect(URL(scheme='https', args=self.args, vars=self.vars))
current.session.secure() current.session.secure()
@@ -329,7 +330,8 @@ class Response(Storage):
stream_file_or_304_or_206(stream, stream_file_or_304_or_206(stream,
chunk_size=chunk_size, chunk_size=chunk_size,
request=request, request=request,
headers=headers) headers=headers,
status=self.status)
# ## the following is for backward compatibility # ## the following is for backward compatibility
if hasattr(stream, 'name'): if hasattr(stream, 'name'):
+2 -2
View File
@@ -1888,7 +1888,7 @@ class SQLFORM(FORM):
rows = dbset.select(cacheable=True) rows = dbset.select(cacheable=True)
else: else:
rows = dbset.select(left=left,orderby=orderby, rows = dbset.select(left=left,orderby=orderby,
cacheable=True*columns) cacheable=True,*columns)
if export_type in exportManager: if export_type in exportManager:
value = exportManager[export_type] value = exportManager[export_type]
@@ -2039,7 +2039,7 @@ class SQLFORM(FORM):
table_fields = [f for f in fields if f._tablename in tablenames] table_fields = [f for f in fields if f._tablename in tablenames]
rows = dbset.select(left=left,orderby=orderby, rows = dbset.select(left=left,orderby=orderby,
groupby=groupby,limitby=limitby, groupby=groupby,limitby=limitby,
cacheable=True,*table_fields) *table_fields)
except SyntaxError: except SyntaxError:
rows = None rows = None
error = T("Query Not Supported") error = T("Query Not Supported")
+30 -26
View File
@@ -43,6 +43,7 @@ def stream_file_or_304_or_206(
chunk_size = DEFAULT_CHUNK_SIZE, chunk_size = DEFAULT_CHUNK_SIZE,
request = None, request = None,
headers = {}, headers = {},
status = 200,
error_message = None, error_message = None,
): ):
if error_message is None: if error_message is None:
@@ -67,32 +68,35 @@ def stream_file_or_304_or_206(
headers.setdefault('Pragma', 'cache') headers.setdefault('Pragma', 'cache')
headers.setdefault('Cache-Control', 'private') headers.setdefault('Cache-Control', 'private')
if request and request.env.http_if_modified_since == mtime: # if this is a normal response and not a respnse to an error page
raise HTTP(304, **{'Content-Type': headers['Content-Type']}) if status == 200:
if request and request.env.http_if_modified_since == mtime:
raise HTTP(304, **{'Content-Type': headers['Content-Type']})
elif request and request.env.http_range: elif request and request.env.http_range:
start_items = regex_start_range.findall(request.env.http_range) start_items = regex_start_range.findall(request.env.http_range)
if not start_items: if not start_items:
start_items = [0] start_items = [0]
stop_items = regex_stop_range.findall(request.env.http_range) stop_items = regex_stop_range.findall(request.env.http_range)
if not stop_items or int(stop_items[0]) > fsize - 1: if not stop_items or int(stop_items[0]) > fsize - 1:
stop_items = [fsize - 1] stop_items = [fsize - 1]
part = (int(start_items[0]), int(stop_items[0]), fsize) part = (int(start_items[0]), int(stop_items[0]), fsize)
bytes = part[1] - part[0] + 1 bytes = part[1] - part[0] + 1
try: try:
stream = open(static_file, 'rb') stream = open(static_file, 'rb')
except IOError, e: except IOError, e:
if e[0] in (errno.EISDIR, errno.EACCES): if e[0] in (errno.EISDIR, errno.EACCES):
raise HTTP(403) raise HTTP(403)
else: else:
raise HTTP(404) raise HTTP(404)
stream.seek(part[0]) stream.seek(part[0])
headers['Content-Range'] = 'bytes %i-%i/%i' % part headers['Content-Range'] = 'bytes %i-%i/%i' % part
headers['Content-Length'] = '%i' % bytes headers['Content-Length'] = '%i' % bytes
status = 206 status = 206
else: # in all the other cases (not 304, not 206, but 200 or error page)
if 'gzip' in request.env.http_accept_encoding and\ if status != 206:
not 'Content-Encoding' in headers: enc = request.env.http_accept_encoding
if enc and 'gzip' in enc and not 'Content-Encoding' in headers:
gzipped = static_file + '.gz' gzipped = static_file + '.gz'
if os.path.isfile(gzipped) and os.path.getmtime(gzipped)>modified: if os.path.isfile(gzipped) and os.path.getmtime(gzipped)>modified:
static_file = gzipped static_file = gzipped
@@ -102,13 +106,13 @@ def stream_file_or_304_or_206(
try: try:
stream = open(static_file, 'rb') stream = open(static_file, 'rb')
except IOError, e: except IOError, e:
# this better does not happer when returning an error page ;-)
if e[0] in (errno.EISDIR, errno.EACCES): if e[0] in (errno.EISDIR, errno.EACCES):
raise HTTP(403) raise HTTP(403)
else: else:
raise HTTP(404) raise HTTP(404)
headers['Content-Length'] = fsize headers['Content-Length'] = fsize
bytes = None bytes = None
status = 200
if request and request.env.web2py_use_wsgi_file_wrapper: if request and request.env.web2py_use_wsgi_file_wrapper:
wrapped = request.env.wsgi_file_wrapper(stream, chunk_size) wrapped = request.env.wsgi_file_wrapper(stream, chunk_size)
else: else:
+1 -1
View File
@@ -4921,7 +4921,7 @@ class Wiki(object):
if query is None: if query is None:
query = (db.wiki_page.id==db.wiki_tag.wiki_page)&\ query = (db.wiki_page.id==db.wiki_tag.wiki_page)&\
(db.wiki_tag.name.belongs(tags)) (db.wiki_tag.name.belongs(tags))
query = query|db.wiki_page.title.startswith(request.vars.q) query = query|db.wiki_page.title.contains(request.vars.q)
if self.restrict_search and not self.manage(): if self.restrict_search and not self.manage():
query = query&(db.wiki_page.created_by==self.auth.user_id) query = query&(db.wiki_page.created_by==self.auth.user_id)
pages = db(query).select(count, pages = db(query).select(count,