예제 #1
0
def _static_interpret_cardinality_violation(_code, err_details):

    if (err_details.constraint_name == 'std::assert_single'
            or err_details.constraint_name == 'std::assert_exists'):
        return errors.CardinalityViolationError(err_details.message)

    elif err_details.constraint_name == 'std::assert_distinct':
        return errors.ConstraintViolationError(err_details.message)

    elif err_details.constraint_name == 'set abstract':
        return errors.ConstraintViolationError(err_details.message)

    return errors.InternalServerError(err_details.message)
예제 #2
0
    def apply(self, spec: spec.Spec,
              storage: typing.Mapping) -> typing.Mapping:

        setting = self.get_setting(spec)
        allow_missing = (self.opcode is OpCode.CONFIG_REM
                         or self.opcode is OpCode.CONFIG_RESET)

        value = self.coerce_value(setting, allow_missing=allow_missing)

        if self.opcode is OpCode.CONFIG_SET:
            if issubclass(setting.type, types.ConfigType):
                raise errors.InternalServerError(
                    f'unexpected CONFIGURE SET on a non-primitive '
                    f'configuration parameter: {self.setting_name}')

            storage = storage.set(self.setting_name, value)

        elif self.opcode is OpCode.CONFIG_RESET:
            if issubclass(setting.type, types.ConfigType):
                raise errors.InternalServerError(
                    f'unexpected CONFIGURE RESET on a non-primitive '
                    f'configuration parameter: {self.setting_name}')

            try:
                storage = storage.delete(self.setting_name)
            except KeyError:
                pass

        elif self.opcode is OpCode.CONFIG_ADD:
            if not issubclass(setting.type, types.ConfigType):
                raise errors.InternalServerError(
                    f'unexpected CONFIGURE SET += on a primitive '
                    f'configuration parameter: {self.setting_name}')

            exist_value = storage.get(self.setting_name, setting.default)
            if value in exist_value:
                props = []
                for f in dataclasses.fields(setting.type):
                    if f.compare:
                        props.append(f.name)

                if len(props) > 1:
                    props = f' ({", ".join(props)}) violate'
                else:
                    props = f'.{props[0]} violates'

                raise errors.ConstraintViolationError(
                    f'{setting.type.__name__}{props} '
                    f'exclusivity constriant')

            new_value = exist_value | {value}
            storage = storage.set(self.setting_name, new_value)

        elif self.opcode is OpCode.CONFIG_REM:
            if not issubclass(setting.type, types.ConfigType):
                raise errors.InternalServerError(
                    f'unexpected CONFIGURE SET -= on a primitive '
                    f'configuration parameter: {self.setting_name}')

            exist_value = storage.get(self.setting_name, setting.default)
            new_value = exist_value - {value}
            storage = storage.set(self.setting_name, new_value)

        return storage
예제 #3
0
def interpret_backend_error(schema, fields):
    err_details = get_error_details(fields)
    # all generic errors are static and have been handled by this point

    if err_details.code == PGErrorCode.NotNullViolationError:
        source_name = pointer_name = None

        if err_details.schema_name and err_details.table_name:
            tabname = (err_details.schema_name, err_details.table_name)

            source = common.get_object_from_backend_name(
                schema, s_objtypes.ObjectType, tabname)
            source_name = source.get_displayname(schema)

            if err_details.column_name:
                pointer_name = err_details.column_name

        if pointer_name is not None:
            pname = f'{source_name}.{pointer_name}'

            return errors.MissingRequiredError(
                f'missing value for required property {pname}')

        else:
            return errors.InternalServerError(err_details.message)

    elif err_details.code in constraint_errors:
        error_type = None

        for errtype, ere in constraint_res.items():
            m = ere.match(err_details.message)
            if m:
                error_type = errtype
                break
        # no need for else clause since it would have been handled by
        # the static version

        # so far 'constraint' is the only expected error_type here,
        # but in the future that might change, so we leave the if
        if error_type == 'constraint':
            # similarly, if we're here it's because we have a constraint_id
            constraint_id, _, _ = err_details.constraint_name.rpartition(';')
            constraint_id = uuid.UUID(constraint_id)

            constraint = schema.get_by_id(constraint_id)

            return errors.ConstraintViolationError(
                constraint.format_error_message(schema))

    elif err_details.code == PGErrorCode.InvalidTextRepresentation:
        return errors.InvalidValueError(
            translate_pgtype(schema, err_details.message))

    elif err_details.code == PGErrorCode.NumericValueOutOfRange:
        return errors.NumericOutOfRangeError(
            translate_pgtype(schema, err_details.message))

    elif err_details.code in {
            PGErrorCode.InvalidDatetimeFormatError, PGErrorCode.DatetimeError
    }:
        return errors.InvalidValueError(
            translate_pgtype(schema, err_details.message))

    return errors.InternalServerError(err_details.message)
예제 #4
0
def static_interpret_backend_error(fields):
    err_details = get_error_details(fields)
    # handle some generic errors if possible
    err = get_generic_exception_from_err_details(err_details)
    if err is not None:
        return err

    if err_details.code == PGErrorCode.NotNullViolationError:
        if err_details.schema_name and err_details.table_name:
            return SchemaRequired

        else:
            return errors.InternalServerError(err_details.message)

    elif err_details.code in constraint_errors:
        source = pointer = None

        for errtype, ere in constraint_res.items():
            m = ere.match(err_details.message)
            if m:
                error_type = errtype
                break
        else:
            return errors.InternalServerError(err_details.message)

        if error_type == 'cardinality':
            return errors.CardinalityViolationError('cardinality violation',
                                                    source=source,
                                                    pointer=pointer)

        elif error_type == 'link_target':
            if err_details.detail_json:
                srcname = err_details.detail_json.get('source')
                ptrname = err_details.detail_json.get('pointer')
                target = err_details.detail_json.get('target')
                expected = err_details.detail_json.get('expected')

                if srcname and ptrname:
                    srcname = sn.Name(srcname)
                    ptrname = sn.Name(ptrname)
                    lname = '{}.{}'.format(srcname, ptrname.name)
                else:
                    lname = ''

                msg = (f'invalid target for link {lname!r}: {target!r} '
                       f'(expecting {expected!r})')

            else:
                msg = 'invalid target for link'

            return errors.UnknownLinkError(msg)

        elif error_type == 'link_target_del':
            return errors.ConstraintViolationError(err_details.message,
                                                   details=err_details.detail)

        elif error_type == 'constraint':
            if err_details.constraint_name is None:
                return errors.InternalServerError(err_details.message)

            constraint_id, _, _ = err_details.constraint_name.rpartition(';')

            try:
                constraint_id = uuid.UUID(constraint_id)
            except ValueError:
                return errors.InternalServerError(err_details.message)

            return SchemaRequired

        elif error_type == 'id':
            return errors.ConstraintViolationError(
                'unique link constraint violation')

    elif err_details.code in SCHEMA_CODES:
        return SchemaRequired

    elif err_details.code == PGErrorCode.InvalidParameterValue:
        return errors.InvalidValueError(
            err_details.message,
            details=err_details.detail if err_details.detail else None)

    elif err_details.code == PGErrorCode.DivisionByZeroError:
        return errors.DivisionByZeroError(err_details.message)

    elif err_details.code == PGErrorCode.ReadOnlySQLTransactionError:
        return errors.TransactionError(
            'cannot execute query in a read-only transaction')

    elif err_details.code == PGErrorCode.TransactionSerializationFailure:
        return errors.TransactionSerializationError(err_details.message)

    elif err_details.code == PGErrorCode.TransactionDeadlockDetected:
        return errors.TransactionDeadlockError(err_details.message)

    return errors.InternalServerError(err_details.message)
예제 #5
0
def interpret_backend_error(schema, fields):
    # See https://www.postgresql.org/docs/current/protocol-error-fields.html
    # for the full list of PostgreSQL error message fields.
    message = fields.get('M')

    detail = fields.get('D')
    detail_json = None
    if detail and detail.startswith('{'):
        detail_json = json.loads(detail)
        detail = None

    if detail_json:
        errcode = detail_json.get('code')
        if errcode:
            try:
                errcls = type(
                    errors.EdgeDBError).get_error_class_from_code(errcode)
            except LookupError:
                pass
            else:
                err = errcls(message)
                err.set_linecol(detail_json.get('line', -1),
                                detail_json.get('column', -1))
                return err

    try:
        code = PGError(fields['C'])
    except ValueError:
        return errors.InternalServerError(message)

    schema_name = fields.get('s')
    table_name = fields.get('t')
    column_name = fields.get('c')
    constraint_name = fields.get('n')

    if code == PGError.NotNullViolationError:
        source_name = pointer_name = None

        if schema_name and table_name:
            tabname = (schema_name, table_name)

            source = common.get_object_from_backend_name(
                schema, s_objtypes.ObjectType, tabname)
            source_name = source.get_displayname(schema)

            if column_name:
                pointer_name = column_name

        if pointer_name is not None:
            pname = f'{source_name}.{pointer_name}'

            return errors.MissingRequiredError(
                f'missing value for required property {pname}')

        else:
            return errors.InternalServerError(message)

    elif code in constraint_errors:
        source = pointer = None

        for errtype, ere in constraint_res.items():
            m = ere.match(message)
            if m:
                error_type = errtype
                break
        else:
            return errors.InternalServerError(message)

        if error_type == 'cardinality':
            return errors.CardinalityViolationError('cardinality violation',
                                                    source=source,
                                                    pointer=pointer)

        elif error_type == 'link_target':
            if detail_json:
                srcname = detail_json.get('source')
                ptrname = detail_json.get('pointer')
                target = detail_json.get('target')
                expected = detail_json.get('expected')

                if srcname and ptrname:
                    srcname = sn.Name(srcname)
                    ptrname = sn.Name(ptrname)
                    lname = '{}.{}'.format(srcname, ptrname.name)
                else:
                    lname = ''

                msg = (f'invalid target for link {lname!r}: {target!r} '
                       f'(expecting {expected!r})')

            else:
                msg = 'invalid target for link'

            return errors.UnknownLinkError(msg)

        elif error_type == 'link_target_del':
            return errors.ConstraintViolationError(message, details=detail)

        elif error_type == 'constraint':
            if constraint_name is None:
                return errors.InternalServerError(message)

            constraint_id, _, _ = constraint_name.rpartition(';')

            try:
                constraint_id = uuid.UUID(constraint_id)
            except ValueError:
                return errors.InternalServerError(message)

            constraint = schema.get_by_id(constraint_id)

            return errors.ConstraintViolationError(
                constraint.format_error_message(schema))

        elif error_type == 'id':
            return errors.ConstraintViolationError(
                'unique link constraint violation')

    elif code == PGError.InvalidParameterValue:
        return errors.InvalidValueError(message,
                                        details=detail if detail else None)

    elif code == PGError.InvalidTextRepresentation:
        return errors.InvalidValueError(translate_pgtype(schema, message))

    elif code == PGError.NumericValueOutOfRange:
        return errors.NumericOutOfRangeError(translate_pgtype(schema, message))

    elif code == PGError.DivisionByZeroError:
        return errors.DivisionByZeroError(message)

    elif code == PGError.ReadOnlySQLTransactionError:
        return errors.TransactionError(
            'cannot execute query in a read-only transaction')

    elif code in {PGError.InvalidDatetimeFormatError, PGError.DatetimeError}:
        return errors.InvalidValueError(translate_pgtype(schema, message))

    elif code == PGError.TransactionSerializationFailure:
        return errors.TransactionSerializationError(message)

    elif code == PGError.TransactionDeadlockDetected:
        return errors.TransactionDeadlockError(message)

    return errors.InternalServerError(message)
예제 #6
0
def interpret_backend_error(schema, fields):
    # See https://www.postgresql.org/docs/current/protocol-error-fields.html
    # for the full list of PostgreSQL error message fields.
    message = fields.get('M')

    try:
        code = PGError(fields['C'])
    except ValueError:
        return errors.InternalServerError(message)

    schema_name = fields.get('s')
    table_name = fields.get('t')
    column_name = fields.get('c')
    detail = fields.get('D')
    constraint_name = fields.get('n')

    if code == PGError.NotNullViolationError:
        source_name = pointer_name = None

        if schema_name and table_name:
            tabname = (schema_name, table_name)

            source = common.get_object_from_backend_name(
                schema, s_objtypes.ObjectType, tabname)
            source_name = source.get_displayname(schema)

            if column_name:
                pointer_name = column_name

        if pointer_name is not None:
            pname = f'{source_name}.{pointer_name}'

            return errors.MissingRequiredError(
                f'missing value for required property {pname}')

        else:
            return errors.InternalServerError(message)

    elif code in constraint_errors:
        source = pointer = None

        for type, ere in constraint_res.items():
            m = ere.match(message)
            if m:
                error_type = type
                break
        else:
            return errors.InternalServerError(message)

        if error_type == 'cardinality':
            return errors.CardinalityViolationError('cardinality violation',
                                                    source=source,
                                                    pointer=pointer)

        elif error_type == 'link_target':
            if detail:
                try:
                    detail = json.loads(detail)
                except ValueError:
                    detail = None

            if detail is not None:
                srcname = detail.get('source')
                ptrname = detail.get('pointer')
                target = detail.get('target')
                expected = detail.get('expected')

                if srcname and ptrname:
                    srcname = sn.Name(srcname)
                    ptrname = sn.Name(ptrname)
                    lname = '{}.{}'.format(srcname, ptrname.name)
                else:
                    lname = ''

                msg = (f'invalid target for link {lname!r}: {target!r} '
                       f'(expecting {expected!r})')

            else:
                msg = 'invalid target for link'

            return errors.UnknownLinkError(msg)

        elif error_type == 'link_target_del':
            return errors.ConstraintViolationError(message, details=detail)

        elif error_type == 'constraint':
            if constraint_name is None:
                return errors.InternalServerError(message)

            constraint_id, _, _ = constraint_name.rpartition(';')

            try:
                constraint_id = uuid.UUID(constraint_id)
            except ValueError:
                return errors.InternalServerError(message)

            constraint = schema.get_by_id(constraint_id)

            return errors.ConstraintViolationError(
                constraint.format_error_message(schema))

        elif error_type == 'id':
            return errors.ConstraintViolationError(
                'unique link constraint violation')

    elif code == PGError.NumericValueOutOfRange:
        return errors.NumericOutOfRangeError(message)

    return errors.InternalServerError(message)
예제 #7
0
def interpret_backend_error(schema, fields):
    err_details = get_error_details(fields)
    hint = None
    details = None
    if err_details.detail_json:
        hint = err_details.detail_json.get('hint')

    # all generic errors are static and have been handled by this point

    if err_details.code == PGErrorCode.NotNullViolationError:
        colname = err_details.column_name
        if colname:
            if colname.startswith('??'):
                ptr_id, *_ = colname[2:].partition('_')
            else:
                ptr_id = colname
            pointer = common.get_object_from_backend_name(
                schema, s_pointers.Pointer, ptr_id)
            pname = pointer.get_verbosename(schema, with_parent=True)
        else:
            pname = None

        if pname is not None:
            if err_details.detail_json:
                object_id = err_details.detail_json.get('object_id')
                if object_id is not None:
                    details = f'Failing object id is {str(object_id)!r}.'

            return errors.MissingRequiredError(
                f'missing value for required {pname}',
                details=details,
                hint=hint,
            )
        else:
            return errors.InternalServerError(err_details.message)

    elif err_details.code in constraint_errors:
        error_type = None
        match = None

        for errtype, ere in constraint_res.items():
            m = ere.match(err_details.message)
            if m:
                error_type = errtype
                match = m
                break
        # no need for else clause since it would have been handled by
        # the static version

        if error_type == 'constraint':
            # similarly, if we're here it's because we have a constraint_id
            constraint_id, _, _ = err_details.constraint_name.rpartition(';')
            constraint_id = uuidgen.UUID(constraint_id)

            constraint = schema.get_by_id(constraint_id)

            return errors.ConstraintViolationError(
                constraint.format_error_message(schema))
        elif error_type == 'newconstraint':
            # If we're here, it means that we already validated that
            # schema_name, table_name and column_name all exist.
            tabname = (err_details.schema_name, err_details.table_name)
            source = common.get_object_from_backend_name(
                schema, s_objtypes.ObjectType, tabname)
            source_name = source.get_displayname(schema)
            pointer = common.get_object_from_backend_name(
                schema, s_pointers.Pointer, err_details.column_name)
            pointer_name = pointer.get_shortname(schema).name

            return errors.ConstraintViolationError(
                f'Existing {source_name}.{pointer_name} '
                f'values violate the new constraint')
        elif error_type == 'scalar':
            domain_name = match.group(1)
            stype_name = types.base_type_name_map_r.get(domain_name)
            if stype_name:
                msg = f'invalid value for scalar type {str(stype_name)!r}'
            else:
                msg = translate_pgtype(schema, err_details.message)
            return errors.InvalidValueError(msg)

    elif err_details.code == PGErrorCode.InvalidTextRepresentation:
        return errors.InvalidValueError(
            translate_pgtype(schema, err_details.message))

    elif err_details.code == PGErrorCode.NumericValueOutOfRange:
        return errors.NumericOutOfRangeError(
            translate_pgtype(schema, err_details.message))

    elif err_details.code in {
            PGErrorCode.InvalidDatetimeFormatError, PGErrorCode.DatetimeError
    }:
        return errors.InvalidValueError(translate_pgtype(
            schema, err_details.message),
                                        hint=hint)

    return errors.InternalServerError(err_details.message)
예제 #8
0
def static_interpret_backend_error(fields):
    err_details = get_error_details(fields)
    # handle some generic errors if possible
    err = get_generic_exception_from_err_details(err_details)
    if err is not None:
        return err

    if err_details.code == PGErrorCode.NotNullViolationError:
        if err_details.table_name or err_details.column_name:
            return SchemaRequired

        else:
            return errors.InternalServerError(err_details.message)

    elif err_details.code in constraint_errors:
        source = pointer = None

        for errtype, ere in constraint_res.items():
            m = ere.match(err_details.message)
            if m:
                error_type = errtype
                break
        else:
            return errors.InternalServerError(err_details.message)

        if error_type == 'cardinality':
            return errors.CardinalityViolationError('cardinality violation',
                                                    source=source,
                                                    pointer=pointer)

        elif error_type == 'link_target':
            if err_details.detail_json:
                srcname = err_details.detail_json.get('source')
                ptrname = err_details.detail_json.get('pointer')
                target = err_details.detail_json.get('target')
                expected = err_details.detail_json.get('expected')

                if srcname and ptrname:
                    srcname = sn.QualName.from_string(srcname)
                    ptrname = sn.QualName.from_string(ptrname)
                    lname = '{}.{}'.format(srcname, ptrname.name)
                else:
                    lname = ''

                msg = (f'invalid target for link {lname!r}: {target!r} '
                       f'(expecting {expected!r})')

            else:
                msg = 'invalid target for link'

            return errors.UnknownLinkError(msg)

        elif error_type == 'link_target_del':
            return errors.ConstraintViolationError(err_details.message,
                                                   details=err_details.detail)

        elif error_type == 'constraint':
            if err_details.constraint_name is None:
                return errors.InternalServerError(err_details.message)

            constraint_id, _, _ = err_details.constraint_name.rpartition(';')

            try:
                constraint_id = uuidgen.UUID(constraint_id)
            except ValueError:
                return errors.InternalServerError(err_details.message)

            return SchemaRequired

        elif error_type == 'newconstraint':
            # We can reconstruct what went wrong from the schema_name,
            # table_name, and column_name. But we don't expect
            # constraint_name to be present (because the constraint is
            # not yet present in the schema?).
            if (err_details.schema_name and err_details.table_name
                    and err_details.column_name):
                return SchemaRequired

            else:
                return errors.InternalServerError(err_details.message)

        elif error_type == 'scalar':
            return SchemaRequired

        elif error_type == 'id':
            return errors.ConstraintViolationError(
                'unique link constraint violation')

    elif err_details.code in SCHEMA_CODES:
        if err_details.code == PGErrorCode.InvalidDatetimeFormatError:
            hint = None
            if err_details.detail_json:
                hint = err_details.detail_json.get('hint')

            if err_details.message.startswith('missing required time zone'):
                return errors.InvalidValueError(err_details.message, hint=hint)
            elif err_details.message.startswith('unexpected time zone'):
                return errors.InvalidValueError(err_details.message, hint=hint)

        return SchemaRequired

    elif err_details.code == PGErrorCode.InvalidParameterValue:
        return errors.InvalidValueError(
            err_details.message,
            details=err_details.detail if err_details.detail else None)

    elif err_details.code == PGErrorCode.WrongObjectType:
        return errors.InvalidValueError(
            err_details.message,
            details=err_details.detail if err_details.detail else None)

    elif err_details.code == PGErrorCode.DivisionByZeroError:
        return errors.DivisionByZeroError(err_details.message)

    elif err_details.code == PGErrorCode.ReadOnlySQLTransactionError:
        return errors.TransactionError(
            'cannot execute query in a read-only transaction')

    elif err_details.code == PGErrorCode.TransactionSerializationFailure:
        return errors.TransactionSerializationError(err_details.message)

    elif err_details.code == PGErrorCode.TransactionDeadlockDetected:
        return errors.TransactionDeadlockError(err_details.message)

    elif err_details.code == PGErrorCode.InvalidCatalogNameError:
        return errors.AuthenticationError(err_details.message)

    elif err_details.code == PGErrorCode.ObjectInUse:
        return errors.ExecutionError(err_details.message)

    return errors.InternalServerError(err_details.message)
예제 #9
0
    async def _interpret_db_error(cls, schema, intro_mech, constr_mech, err):
        if isinstance(err, asyncpg.NotNullViolationError):
            source_name = pointer_name = None

            if err.schema_name and err.table_name:
                tabname = (err.schema_name, err.table_name)

                source = common.get_object_from_backend_name(
                    schema, s_objtypes.ObjectType, tabname)
                source_name = source.get_displayname(schema)

                if err.column_name:
                    pointer_name = err.column_name

            if pointer_name is not None:
                pname = f'{source_name}.{pointer_name}'

                return errors.MissingRequiredError(
                    'missing value for required property {}'.format(pname),
                    source_name=source_name,
                    pointer_name=pointer_name)

            else:
                return errors.InternalServerError(err.message)

        elif isinstance(err, asyncpg.IntegrityConstraintViolationError):
            source = pointer = None

            for ecls, eres in cls.error_res.items():
                if isinstance(err, ecls):
                    break
            else:
                eres = {}

            for type, ere in eres.items():
                m = ere.match(err.message)
                if m:
                    error_type = type
                    break
            else:
                return errors.InternalServerError(err.message)

            if error_type == 'cardinality':
                err = 'cardinality violation'
                errcls = errors.CardinalityViolationError
                return errcls(err, source=source, pointer=pointer)

            elif error_type == 'link_target':
                if err.detail:
                    try:
                        detail = json.loads(err.detail)
                    except ValueError:
                        detail = None

                if detail is not None:
                    srcname = detail.get('source')
                    ptrname = detail.get('pointer')
                    target = detail.get('target')
                    expected = detail.get('expected')

                    if srcname and ptrname:
                        srcname = sn.Name(srcname)
                        ptrname = sn.Name(ptrname)
                        lname = '{}.{}'.format(srcname, ptrname.name)
                    else:
                        lname = ''

                    msg = 'invalid target for link {!r}: {!r} (' \
                          'expecting {!r})'.format(lname, target,
                                                   ' or '.join(expected))

                else:
                    msg = 'invalid target for link'

                return errors.UnknownLinkError(msg)

            elif error_type == 'link_target_del':
                return errors.ConstraintViolationError(err.message,
                                                       detail=err.detail)

            elif error_type == 'constraint':
                if err.constraint_name is None:
                    return errors.InternalServerError(err.message)

                constraint_id, _, _ = err.constraint_name.rpartition(';')

                try:
                    constraint_id = uuid.UUID(constraint_id)
                except ValueError:
                    return errors.InternalServerError(err.message)

                constraint = schema.get_by_id(constraint_id)

                return errors.ConstraintViolationError(
                    constraint.format_error_message(schema))

            elif error_type == 'id':
                msg = 'unique link constraint violation'
                errcls = errors.ConstraintViolationError
                return errcls(msg=msg)

        else:
            return errors.InternalServerError(err.message)
예제 #10
0
def interpret_backend_error(schema, fields):
    err_details = get_error_details(fields)
    hint = None
    details = None
    if err_details.detail_json:
        hint = err_details.detail_json.get('hint')

    # all generic errors are static and have been handled by this point

    if err_details.code == pgerrors.ERROR_NOT_NULL_VIOLATION:
        colname = err_details.column_name
        if colname:
            if colname.startswith('??'):
                ptr_id, *_ = colname[2:].partition('_')
            else:
                ptr_id = colname
            pointer = common.get_object_from_backend_name(
                schema, s_pointers.Pointer, ptr_id)
            pname = pointer.get_verbosename(schema, with_parent=True)
        else:
            pname = None

        if pname is not None:
            if err_details.detail_json:
                object_id = err_details.detail_json.get('object_id')
                if object_id is not None:
                    details = f'Failing object id is {str(object_id)!r}.'

            return errors.MissingRequiredError(
                f'missing value for required {pname}',
                details=details,
                hint=hint,
            )
        else:
            return errors.InternalServerError(err_details.message)

    elif err_details.code in constraint_errors:
        error_type = None
        match = None

        for errtype, ere in constraint_res.items():
            m = ere.match(err_details.message)
            if m:
                error_type = errtype
                match = m
                break
        # no need for else clause since it would have been handled by
        # the static version

        if error_type == 'constraint':
            # similarly, if we're here it's because we have a constraint_id
            constraint_id, _, _ = err_details.constraint_name.rpartition(';')
            constraint_id = uuidgen.UUID(constraint_id)

            constraint = schema.get_by_id(constraint_id)

            return errors.ConstraintViolationError(
                constraint.format_error_message(schema))
        elif error_type == 'newconstraint':
            # If we're here, it means that we already validated that
            # schema_name, table_name and column_name all exist.
            tabname = (err_details.schema_name, err_details.table_name)
            source = common.get_object_from_backend_name(
                schema, s_objtypes.ObjectType, tabname)
            source_name = source.get_displayname(schema)
            pointer = common.get_object_from_backend_name(
                schema, s_pointers.Pointer, err_details.column_name)
            pointer_name = pointer.get_shortname(schema).name

            return errors.ConstraintViolationError(
                f'Existing {source_name}.{pointer_name} '
                f'values violate the new constraint')
        elif error_type == 'scalar':
            domain_name = match.group(1)
            stype_name = types.base_type_name_map_r.get(domain_name)
            if stype_name:
                if match.group(2) in range_constraints:
                    msg = f'{str(stype_name)!r} value out of range'
                else:
                    msg = f'invalid value for scalar type {str(stype_name)!r}'
            else:
                msg = translate_pgtype(schema, err_details.message)
            return errors.InvalidValueError(msg)

    elif err_details.code == pgerrors.ERROR_INVALID_TEXT_REPRESENTATION:
        return errors.InvalidValueError(
            translate_pgtype(schema, err_details.message))

    elif err_details.code == pgerrors.ERROR_NUMERIC_VALUE_OUT_OF_RANGE:
        return errors.NumericOutOfRangeError(
            translate_pgtype(schema, err_details.message))

    elif err_details.code in {pgerrors.ERROR_INVALID_DATETIME_FORMAT,
                              pgerrors.ERROR_DATETIME_FIELD_OVERFLOW}:
        return errors.InvalidValueError(
            translate_pgtype(schema, err_details.message),
            hint=hint)

    elif (
        err_details.code == pgerrors.ERROR_WRONG_OBJECT_TYPE
        and err_details.message == 'covariance error'
    ):
        ptr = schema.get_by_id(uuidgen.UUID(err_details.column_name))
        wrong_obj = schema.get_by_id(uuidgen.UUID(err_details.table_name))

        vn = ptr.get_verbosename(schema, with_parent=True)
        return errors.InvalidLinkTargetError(
            f"invalid target for {vn}: '{wrong_obj.get_name(schema)}'"
            f" (expecting '{ptr.get_target(schema).get_name(schema)}')"
        )

    return errors.InternalServerError(err_details.message)
예제 #11
0
def static_interpret_backend_error(fields):
    err_details = get_error_details(fields)
    # handle some generic errors if possible
    err = get_generic_exception_from_err_details(err_details)
    if err is not None:
        return err

    if err_details.code == pgerrors.ERROR_NOT_NULL_VIOLATION:
        if err_details.table_name or err_details.column_name:
            return SchemaRequired

        else:
            return errors.InternalServerError(err_details.message)

    elif err_details.code in constraint_errors:
        source = pointer = None

        for errtype, ere in constraint_res.items():
            m = ere.match(err_details.message)
            if m:
                error_type = errtype
                break
        else:
            return errors.InternalServerError(err_details.message)

        if error_type == 'cardinality':
            return errors.CardinalityViolationError(
                'cardinality violation',
                source=source, pointer=pointer)

        elif error_type == 'link_target':
            if err_details.detail_json:
                srcname = err_details.detail_json.get('source')
                ptrname = err_details.detail_json.get('pointer')
                target = err_details.detail_json.get('target')
                expected = err_details.detail_json.get('expected')

                if srcname and ptrname:
                    srcname = sn.QualName.from_string(srcname)
                    ptrname = sn.QualName.from_string(ptrname)
                    lname = '{}.{}'.format(srcname, ptrname.name)
                else:
                    lname = ''

                msg = (
                    f'invalid target for link {lname!r}: {target!r} '
                    f'(expecting {expected!r})'
                )

            else:
                msg = 'invalid target for link'

            return errors.UnknownLinkError(msg)

        elif error_type == 'link_target_del':
            return errors.ConstraintViolationError(
                err_details.message, details=err_details.detail)

        elif error_type == 'constraint':
            if err_details.constraint_name is None:
                return errors.InternalServerError(err_details.message)

            constraint_id, _, _ = err_details.constraint_name.rpartition(';')

            try:
                constraint_id = uuidgen.UUID(constraint_id)
            except ValueError:
                return errors.InternalServerError(err_details.message)

            return SchemaRequired

        elif error_type == 'newconstraint':
            # We can reconstruct what went wrong from the schema_name,
            # table_name, and column_name. But we don't expect
            # constraint_name to be present (because the constraint is
            # not yet present in the schema?).
            if (err_details.schema_name and err_details.table_name and
                    err_details.column_name):
                return SchemaRequired

            else:
                return errors.InternalServerError(err_details.message)

        elif error_type == 'scalar':
            return SchemaRequired

        elif error_type == 'id':
            return errors.ConstraintViolationError(
                'unique link constraint violation')

    elif err_details.code in SCHEMA_CODES:
        if err_details.code == pgerrors.ERROR_INVALID_DATETIME_FORMAT:
            hint = None
            if err_details.detail_json:
                hint = err_details.detail_json.get('hint')

            if err_details.message.startswith('missing required time zone'):
                return errors.InvalidValueError(err_details.message, hint=hint)
            elif err_details.message.startswith('unexpected time zone'):
                return errors.InvalidValueError(err_details.message, hint=hint)

        return SchemaRequired

    elif err_details.code == pgerrors.ERROR_INVALID_PARAMETER_VALUE:
        return errors.InvalidValueError(
            err_details.message,
            details=err_details.detail if err_details.detail else None
        )

    elif err_details.code == pgerrors.ERROR_WRONG_OBJECT_TYPE:
        if err_details.column_name:
            return SchemaRequired

        return errors.InvalidValueError(
            err_details.message,
            details=err_details.detail if err_details.detail else None
        )

    elif err_details.code == pgerrors.ERROR_DIVISION_BY_ZERO:
        return errors.DivisionByZeroError(err_details.message)

    elif err_details.code == pgerrors.ERROR_INTERVAL_FIELD_OVERFLOW:
        return errors.NumericOutOfRangeError(err_details.message)

    elif err_details.code == pgerrors.ERROR_READ_ONLY_SQL_TRANSACTION:
        return errors.TransactionError(
            'cannot execute query in a read-only transaction')

    elif err_details.code == pgerrors.ERROR_SERIALIZATION_FAILURE:
        return errors.TransactionSerializationError(err_details.message)

    elif err_details.code == pgerrors.ERROR_DEADLOCK_DETECTED:
        return errors.TransactionDeadlockError(err_details.message)

    elif err_details.code == pgerrors.ERROR_INVALID_CATALOG_NAME:
        return errors.UnknownDatabaseError(err_details.message)

    elif err_details.code == pgerrors.ERROR_OBJECT_IN_USE:
        return errors.ExecutionError(err_details.message)

    elif err_details.code == pgerrors.ERROR_DUPLICATE_DATABASE:
        return errors.DuplicateDatabaseDefinitionError(err_details.message)

    elif (
        err_details.code == pgerrors.ERROR_CARDINALITY_VIOLATION
        and err_details.constraint_name == 'std::assert_single'
    ):
        return errors.CardinalityViolationError(err_details.message)

    return errors.InternalServerError(err_details.message)
예제 #12
0
def _interpret_constraint_errors(code, schema, err_details, hint):
    details = None
    if code == pgerrors.ERROR_NOT_NULL_VIOLATION:
        colname = err_details.column_name
        if colname:
            if colname.startswith('??'):
                ptr_id, *_ = colname[2:].partition('_')
            else:
                ptr_id = colname
            pointer = common.get_object_from_backend_name(
                schema, s_pointers.Pointer, ptr_id)
            pname = pointer.get_verbosename(schema, with_parent=True)
        else:
            pname = None

        if pname is not None:
            if err_details.detail_json:
                object_id = err_details.detail_json.get('object_id')
                if object_id is not None:
                    details = f'Failing object id is {str(object_id)!r}.'

            return errors.MissingRequiredError(
                f'missing value for required {pname}',
                details=details,
                hint=hint,
            )
        else:
            return errors.InternalServerError(err_details.message)

    error_type = None
    match = None

    for errtype, ere in constraint_res.items():
        m = ere.match(err_details.message)
        if m:
            error_type = errtype
            match = m
            break
    # no need for else clause since it would have been handled by
    # the static version

    if error_type == 'constraint':
        # similarly, if we're here it's because we have a constraint_id
        constraint_id, _, _ = err_details.constraint_name.rpartition(';')
        constraint_id = uuidgen.UUID(constraint_id)

        constraint = schema.get_by_id(constraint_id)

        msg = constraint.format_error(schema)
        subject = constraint.get_subject(schema)
        vname = subject.get_verbosename(schema, with_parent=True)
        subjtitle = f"value of {vname}"
        details = constraint.format_error_message(schema, subjtitle)
        return errors.ConstraintViolationError(msg, details=details)
    elif error_type == 'newconstraint':
        # If we're here, it means that we already validated that
        # schema_name, table_name and column_name all exist.
        tabname = (err_details.schema_name, err_details.table_name)
        source = common.get_object_from_backend_name(schema,
                                                     s_objtypes.ObjectType,
                                                     tabname)
        source_name = source.get_displayname(schema)
        pointer = common.get_object_from_backend_name(schema,
                                                      s_pointers.Pointer,
                                                      err_details.column_name)
        pointer_name = pointer.get_shortname(schema).name

        return errors.ConstraintViolationError(
            f'Existing {source_name}.{pointer_name} '
            f'values violate the new constraint')
    elif error_type == 'scalar':
        domain_name = match.group(1)
        stype_name = types.base_type_name_map_r.get(domain_name)
        if stype_name:
            if match.group(2) in range_constraints:
                msg = f'{str(stype_name)!r} value out of range'
            else:
                msg = f'invalid value for scalar type {str(stype_name)!r}'
        else:
            msg = translate_pgtype(schema, err_details.message)
        return errors.InvalidValueError(msg)

    return errors.InternalServerError(err_details.message)
예제 #13
0
def _static_interpret_constraint_errors(code, err_details):
    if code == pgerrors.ERROR_NOT_NULL_VIOLATION:
        if err_details.table_name or err_details.column_name:
            return SchemaRequired
        else:
            return errors.InternalServerError(err_details.message)

    source = pointer = None

    for errtype, ere in constraint_res.items():
        m = ere.match(err_details.message)
        if m:
            error_type = errtype
            break
    else:
        return errors.InternalServerError(err_details.message)

    if error_type == 'cardinality':
        return errors.CardinalityViolationError('cardinality violation',
                                                source=source,
                                                pointer=pointer)

    elif error_type == 'link_target':
        if err_details.detail_json:
            srcname = err_details.detail_json.get('source')
            ptrname = err_details.detail_json.get('pointer')
            target = err_details.detail_json.get('target')
            expected = err_details.detail_json.get('expected')

            if srcname and ptrname:
                srcname = sn.QualName.from_string(srcname)
                ptrname = sn.QualName.from_string(ptrname)
                lname = '{}.{}'.format(srcname, ptrname.name)
            else:
                lname = ''

            msg = (f'invalid target for link {lname!r}: {target!r} '
                   f'(expecting {expected!r})')

        else:
            msg = 'invalid target for link'

        return errors.UnknownLinkError(msg)

    elif error_type == 'link_target_del':
        return errors.ConstraintViolationError(err_details.message,
                                               details=err_details.detail)

    elif error_type == 'constraint':
        if err_details.constraint_name is None:
            return errors.InternalServerError(err_details.message)

        constraint_id, _, _ = err_details.constraint_name.rpartition(';')

        try:
            constraint_id = uuidgen.UUID(constraint_id)
        except ValueError:
            return errors.InternalServerError(err_details.message)

        return SchemaRequired

    elif error_type == 'newconstraint':
        # We can reconstruct what went wrong from the schema_name,
        # table_name, and column_name. But we don't expect
        # constraint_name to be present (because the constraint is
        # not yet present in the schema?).
        if (err_details.schema_name and err_details.table_name
                and err_details.column_name):
            return SchemaRequired

        else:
            return errors.InternalServerError(err_details.message)

    elif error_type == 'scalar':
        return SchemaRequired

    elif error_type == 'id':
        return errors.ConstraintViolationError(
            'unique link constraint violation')