Revision 5577
Added by Aaron Marcuse-Kubitza about 12 years ago
sql.py | ||
---|---|---|
496 | 496 |
|
497 | 497 |
##### Recoverable querying |
498 | 498 |
|
499 |
def parse_exception(db, e, recover=False): |
|
500 |
msg = strings.ustr(e.args[0]) |
|
501 |
msg = re.sub(r'^(?:PL/Python: )?ValueError: ', r'', msg) |
|
502 |
|
|
503 |
match = re.match(r'^invalid byte sequence for encoding "(.+?)":', msg) |
|
504 |
if match: |
|
505 |
encoding, = match.groups() |
|
506 |
raise EncodingException(encoding, e) |
|
507 |
|
|
508 |
match = re.match(r'^duplicate key value violates unique constraint "(.+?)"', |
|
509 |
msg) |
|
510 |
if match: |
|
511 |
constraint, = match.groups() |
|
512 |
cols = [] |
|
513 |
cond = None |
|
514 |
if recover: # need auto-rollback to run index_cols() |
|
515 |
try: |
|
516 |
cols = index_cols(db, constraint) |
|
517 |
cond = index_cond(db, constraint) |
|
518 |
except NotImplementedError: pass |
|
519 |
raise DuplicateKeyException(constraint, cond, cols, e) |
|
520 |
|
|
521 |
match = re.match(r'^null value in column "(.+?)" violates not-null' |
|
522 |
r' constraint', msg) |
|
523 |
if match: |
|
524 |
col, = match.groups() |
|
525 |
raise NullValueException('NOT NULL', None, [col], e) |
|
526 |
|
|
527 |
match = re.match(r'^new row for relation "(.+?)" violates check ' |
|
528 |
r'constraint "(.+?)"', msg) |
|
529 |
if match: |
|
530 |
table, constraint = match.groups() |
|
531 |
constraint = sql_gen.Col(constraint, table) |
|
532 |
cond = None |
|
533 |
if recover: # need auto-rollback to run constraint_cond() |
|
534 |
try: cond = constraint_cond(db, constraint) |
|
535 |
except NotImplementedError: pass |
|
536 |
raise CheckException(constraint.to_str(db), cond, [], e) |
|
537 |
|
|
538 |
match = re.match(r'^(?:invalid input (?:syntax|value)\b.*?' |
|
539 |
r'|.+? out of range): "(.+?)"', msg) |
|
540 |
if match: |
|
541 |
value, = match.groups() |
|
542 |
raise InvalidValueException(strings.to_unicode(value), e) |
|
543 |
|
|
544 |
match = re.match(r'^column "(.+?)" is of type (.+?) but expression ' |
|
545 |
r'is of type', msg) |
|
546 |
if match: |
|
547 |
col, type_ = match.groups() |
|
548 |
raise MissingCastException(type_, col, e) |
|
549 |
|
|
550 |
match = re.match(r'^could not determine polymorphic type because ' |
|
551 |
r'input has type "unknown"', msg) |
|
552 |
if match: raise MissingCastException('text', None, e) |
|
553 |
|
|
554 |
match = re.match(r'^.+? types .+? and .+? cannot be matched', msg) |
|
555 |
if match: raise MissingCastException('text', None, e) |
|
556 |
|
|
557 |
typed_name_re = r'^(\S+) "(.+?)"(?: of relation ".+?")?' |
|
558 |
|
|
559 |
match = re.match(typed_name_re+r'.*? already exists', msg) |
|
560 |
if match: |
|
561 |
type_, name = match.groups() |
|
562 |
raise DuplicateException(type_, name, e) |
|
563 |
|
|
564 |
match = re.match(r'more than one (\S+) named ""(.+?)""', msg) |
|
565 |
if match: |
|
566 |
type_, name = match.groups() |
|
567 |
raise DuplicateException(type_, name, e) |
|
568 |
|
|
569 |
match = re.match(typed_name_re+r' does not exist', msg) |
|
570 |
if match: |
|
571 |
type_, name = match.groups() |
|
572 |
raise DoesNotExistException(type_, name, e) |
|
573 |
|
|
574 |
raise # no specific exception raised |
|
575 |
|
|
499 | 576 |
def with_savepoint(db, func): return db.with_savepoint(func) |
500 | 577 |
|
501 | 578 |
def run_query(db, query, recover=None, cacheable=False, log_level=2, |
... | ... | |
515 | 592 |
if recover and not db.is_cached(query): |
516 | 593 |
return with_savepoint(db, run) |
517 | 594 |
else: return run() # don't need savepoint if cached |
518 |
except Exception, e: |
|
519 |
msg = strings.ustr(e.args[0]) |
|
520 |
msg = re.sub(r'^(?:PL/Python: )?ValueError: ', r'', msg) |
|
521 |
|
|
522 |
match = re.match(r'^invalid byte sequence for encoding "(.+?)":', |
|
523 |
msg) |
|
524 |
if match: |
|
525 |
encoding, = match.groups() |
|
526 |
raise EncodingException(encoding, e) |
|
527 |
|
|
528 |
match = re.match(r'^duplicate key value violates unique constraint ' |
|
529 |
r'"(.+?)"', msg) |
|
530 |
if match: |
|
531 |
constraint, = match.groups() |
|
532 |
cols = [] |
|
533 |
cond = None |
|
534 |
if recover: # need auto-rollback to run index_cols() |
|
535 |
try: |
|
536 |
cols = index_cols(db, constraint) |
|
537 |
cond = index_cond(db, constraint) |
|
538 |
except NotImplementedError: pass |
|
539 |
raise DuplicateKeyException(constraint, cond, cols, e) |
|
540 |
|
|
541 |
match = re.match(r'^null value in column "(.+?)" violates not-null' |
|
542 |
r' constraint', msg) |
|
543 |
if match: |
|
544 |
col, = match.groups() |
|
545 |
raise NullValueException('NOT NULL', None, [col], e) |
|
546 |
|
|
547 |
match = re.match(r'^new row for relation "(.+?)" violates check ' |
|
548 |
r'constraint "(.+?)"', msg) |
|
549 |
if match: |
|
550 |
table, constraint = match.groups() |
|
551 |
constraint = sql_gen.Col(constraint, table) |
|
552 |
cond = None |
|
553 |
if recover: # need auto-rollback to run constraint_cond() |
|
554 |
try: cond = constraint_cond(db, constraint) |
|
555 |
except NotImplementedError: pass |
|
556 |
raise CheckException(constraint.to_str(db), cond, [], e) |
|
557 |
|
|
558 |
match = re.match(r'^(?:invalid input (?:syntax|value)\b.*?' |
|
559 |
r'|.+? out of range): "(.+?)"', msg) |
|
560 |
if match: |
|
561 |
value, = match.groups() |
|
562 |
raise InvalidValueException(strings.to_unicode(value), e) |
|
563 |
|
|
564 |
match = re.match(r'^column "(.+?)" is of type (.+?) but expression ' |
|
565 |
r'is of type', msg) |
|
566 |
if match: |
|
567 |
col, type_ = match.groups() |
|
568 |
raise MissingCastException(type_, col, e) |
|
569 |
|
|
570 |
match = re.match(r'^could not determine polymorphic type because ' |
|
571 |
r'input has type "unknown"', msg) |
|
572 |
if match: raise MissingCastException('text', None, e) |
|
573 |
|
|
574 |
match = re.match(r'^.+? types .+? and .+? cannot be matched', msg) |
|
575 |
if match: raise MissingCastException('text', None, e) |
|
576 |
|
|
577 |
typed_name_re = r'^(\S+) "(.+?)"(?: of relation ".+?")?' |
|
578 |
|
|
579 |
match = re.match(typed_name_re+r'.*? already exists', msg) |
|
580 |
if match: |
|
581 |
type_, name = match.groups() |
|
582 |
raise DuplicateException(type_, name, e) |
|
583 |
|
|
584 |
match = re.match(r'more than one (\S+) named ""(.+?)""', msg) |
|
585 |
if match: |
|
586 |
type_, name = match.groups() |
|
587 |
raise DuplicateException(type_, name, e) |
|
588 |
|
|
589 |
match = re.match(typed_name_re+r' does not exist', msg) |
|
590 |
if match: |
|
591 |
type_, name = match.groups() |
|
592 |
raise DoesNotExistException(type_, name, e) |
|
593 |
|
|
594 |
raise # no specific exception raised |
|
595 |
except Exception, e: parse_exception(db, e, recover) |
|
595 | 596 |
except log_ignore_excs: |
596 | 597 |
log_level += 2 |
597 | 598 |
raise |
Also available in: Unified diff
sql.py: run_query(): Factored exception parsing out into new parse_exception()