def _get_column_info(self, *args, **kwargs):
        kw = kwargs.copy()
        encode = kw.pop('encode', None)
        if sa_version >= Version('1.3.16'):
            # SQLAlchemy 1.3.16 introduced generated columns,
            # not supported in redshift
            kw['generated'] = ''

        if sa_version < Version('1.4.0') and 'identity' in kw:
            del kw['identity']
        elif sa_version >= Version('1.4.0') and 'identity' not in kw:
            kw['identity'] = None

        column_info = super(RedshiftDialectMixin, self)._get_column_info(
            *args,
            **kw
        )
        if isinstance(column_info['type'], VARCHAR):
            if column_info['type'].length is None:
                column_info['type'] = NullType()
        if 'info' not in column_info:
            column_info['info'] = {}
        if encode and encode != 'none':
            column_info['info']['encode'] = encode
        return column_info
Ejemplo n.º 2
0
 def _get_column_info(self, name, format_type, default, notnull, domains,
                      enums, schema):
     column_info = super(RedshiftDialect,
                         self)._get_column_info(name, format_type, default,
                                                notnull, domains, enums,
                                                schema)
     if isinstance(column_info['type'],
                   VARCHAR) and column_info['type'].length is None:
         column_info['type'] = NullType()
     return column_info
Ejemplo n.º 3
0
    def test_typing_construction(self):
        t = text("select * from table :foo :bar :bat")

        self._assert_type_map(t, {
            "foo": NullType(),
            "bar": NullType(),
            "bat": NullType()
        })

        t = t.bindparams(bindparam("foo", type_=String))

        self._assert_type_map(t, {
            "foo": String(),
            "bar": NullType(),
            "bat": NullType()
        })

        t = t.bindparams(bindparam("bar", type_=Integer))

        self._assert_type_map(t, {
            "foo": String(),
            "bar": Integer(),
            "bat": NullType()
        })

        t = t.bindparams(bat=45.564)

        self._assert_type_map(t, {
            "foo": String(),
            "bar": Integer(),
            "bat": Float()
        })
Ejemplo n.º 4
0
 def _get_column_info(self, *args, **kwargs):
     kw = kwargs.copy()
     encode = kw.pop('encode', None)
     column_info = super(RedshiftDialect,
                         self)._get_column_info(*args, **kw)
     if isinstance(column_info['type'], VARCHAR):
         if column_info['type'].length is None:
             column_info['type'] = NullType()
     if 'info' not in column_info:
         column_info['info'] = {}
     if encode and encode != 'none':
         column_info['info']['encode'] = encode
     return column_info
Ejemplo n.º 5
0
 def _get_column_info(self, *args, **kwargs):
     kw = kwargs.copy()
     encode = kw.pop('encode', None)
     if sa.__version__ < '1.2.0':
         # SQLAlchemy 1.2.0 introduced the 'comment' param
         del kw['comment']
     column_info = super(RedshiftDialect,
                         self)._get_column_info(*args, **kw)
     if isinstance(column_info['type'], VARCHAR):
         if column_info['type'].length is None:
             column_info['type'] = NullType()
     if 'info' not in column_info:
         column_info['info'] = {}
     if encode and encode != 'none':
         column_info['info']['encode'] = encode
     return column_info
Ejemplo n.º 6
0
    def ordered_values(self, *args):
        """Specify the VALUES clause of this UPDATE statement with an explicit
        parameter ordering that will be maintained in the SET clause of the
        resulting UPDATE statement.

        E.g.::

            stmt = table.update().ordered_values(
                ("name", "ed"), ("ident": "foo")
            )

        .. seealso::

           :ref:`updates_order_parameters` - full example of the
           :meth:`_expression.Update.ordered_values` method.

        .. versionchanged:: 1.4 The :meth:`_expression.Update.ordered_values`
           method
           supersedes the
           :paramref:`_expression.update.preserve_parameter_order`
           parameter, which will be removed in SQLAlchemy 2.0.

        """
        if self._values:
            raise exc.ArgumentError(
                "This statement already has values present"
            )
        elif self._ordered_values:
            raise exc.ArgumentError(
                "This statement already has ordered values present"
            )
        arg = [
            (
                coercions.expect(roles.DMLColumnRole, k),
                coercions.expect(
                    roles.ExpressionElementRole,
                    v,
                    type_=NullType(),
                    is_crud=True,
                ),
            )
            for k, v in args
        ]
        self._ordered_values = arg
Ejemplo n.º 7
0
 def col2_dict(key):
     return {
         'name': 'col2',
         'type': NullType()
     }.get(key, Mock())
Ejemplo n.º 8
0
    def values(self, *args, **kwargs):
        r"""Specify a fixed VALUES clause for an INSERT statement, or the SET
        clause for an UPDATE.

        Note that the :class:`_expression.Insert` and
        :class:`_expression.Update`
        constructs support
        per-execution time formatting of the VALUES and/or SET clauses,
        based on the arguments passed to :meth:`_engine.Connection.execute`.
        However, the :meth:`.ValuesBase.values` method can be used to "fix" a
        particular set of parameters into the statement.

        Multiple calls to :meth:`.ValuesBase.values` will produce a new
        construct, each one with the parameter list modified to include
        the new parameters sent.  In the typical case of a single
        dictionary of parameters, the newly passed keys will replace
        the same keys in the previous construct.  In the case of a list-based
        "multiple values" construct, each new list of values is extended
        onto the existing list of values.

        :param \**kwargs: key value pairs representing the string key
          of a :class:`_schema.Column`
          mapped to the value to be rendered into the
          VALUES or SET clause::

                users.insert().values(name="some name")

                users.update().where(users.c.id==5).values(name="some name")

        :param \*args: As an alternative to passing key/value parameters,
         a dictionary, tuple, or list of dictionaries or tuples can be passed
         as a single positional argument in order to form the VALUES or
         SET clause of the statement.  The forms that are accepted vary
         based on whether this is an :class:`_expression.Insert` or an
         :class:`_expression.Update` construct.

         For either an :class:`_expression.Insert` or
         :class:`_expression.Update`
         construct, a single dictionary can be passed, which works the same as
         that of the kwargs form::

            users.insert().values({"name": "some name"})

            users.update().values({"name": "some new name"})

         Also for either form but more typically for the
         :class:`_expression.Insert` construct, a tuple that contains an
         entry for every column in the table is also accepted::

            users.insert().values((5, "some name"))

         The :class:`_expression.Insert` construct also supports being
         passed a list of dictionaries or full-table-tuples, which on the
         server will render the less common SQL syntax of "multiple values" -
         this syntax is supported on backends such as SQLite, PostgreSQL,
         MySQL, but not necessarily others::

            users.insert().values([
                                {"name": "some name"},
                                {"name": "some other name"},
                                {"name": "yet another name"},
                            ])

         The above form would render a multiple VALUES statement similar to::

                INSERT INTO users (name) VALUES
                                (:name_1),
                                (:name_2),
                                (:name_3)

         It is essential to note that **passing multiple values is
         NOT the same as using traditional executemany() form**.  The above
         syntax is a **special** syntax not typically used.  To emit an
         INSERT statement against multiple rows, the normal method is
         to pass a multiple values list to the
         :meth:`_engine.Connection.execute`
         method, which is supported by all database backends and is generally
         more efficient for a very large number of parameters.

           .. seealso::

               :ref:`execute_multiple` - an introduction to
               the traditional Core method of multiple parameter set
               invocation for INSERTs and other statements.

           .. versionchanged:: 1.0.0 an INSERT that uses a multiple-VALUES
              clause, even a list of length one,
              implies that the :paramref:`_expression.Insert.inline`
              flag is set to
              True, indicating that the statement will not attempt to fetch
              the "last inserted primary key" or other defaults.  The
              statement deals with an arbitrary number of rows, so the
              :attr:`_engine.CursorResult.inserted_primary_key`
              accessor does not
              apply.

           .. versionchanged:: 1.0.0 A multiple-VALUES INSERT now supports
              columns with Python side default values and callables in the
              same way as that of an "executemany" style of invocation; the
              callable is invoked for each row.   See :ref:`bug_3288`
              for other details.

          The UPDATE construct also supports rendering the SET parameters
          in a specific order.  For this feature refer to the
          :meth:`_expression.Update.ordered_values` method.

           .. seealso::

              :meth:`_expression.Update.ordered_values`

        .. seealso::

            :ref:`inserts_and_updates` - SQL Expression
            Language Tutorial

            :func:`_expression.insert` - produce an ``INSERT`` statement

            :func:`_expression.update` - produce an ``UPDATE`` statement

        """
        if self._select_names:
            raise exc.InvalidRequestError(
                "This construct already inserts from a SELECT")
        elif self._ordered_values:
            raise exc.ArgumentError(
                "This statement already has ordered values present")

        if args:
            # positional case.  this is currently expensive.   we don't
            # yet have positional-only args so we have to check the length.
            # then we need to check multiparams vs. single dictionary.
            # since the parameter format is needed in order to determine
            # a cache key, we need to determine this up front.
            arg = args[0]

            if kwargs:
                raise exc.ArgumentError(
                    "Can't pass positional and kwargs to values() "
                    "simultaneously")
            elif len(args) > 1:
                raise exc.ArgumentError(
                    "Only a single dictionary/tuple or list of "
                    "dictionaries/tuples is accepted positionally.")

            elif not self._preserve_parameter_order and isinstance(
                    arg, collections_abc.Sequence):

                if arg and isinstance(arg[0], (list, dict, tuple)):
                    self._multi_values += (arg, )
                    return

                # tuple values
                arg = {c.key: value for c, value in zip(self.table.c, arg)}
            elif self._preserve_parameter_order and not isinstance(
                    arg, collections_abc.Sequence):
                raise ValueError("When preserve_parameter_order is True, "
                                 "values() only accepts a list of 2-tuples")

        else:
            # kwarg path.  this is the most common path for non-multi-params
            # so this is fairly quick.
            arg = kwargs
            if args:
                raise exc.ArgumentError(
                    "Only a single dictionary/tuple or list of "
                    "dictionaries/tuples is accepted positionally.")

        # for top level values(), convert literals to anonymous bound
        # parameters at statement construction time, so that these values can
        # participate in the cache key process like any other ClauseElement.
        # crud.py now intercepts bound parameters with unique=True from here
        # and ensures they get the "crud"-style name when rendered.

        if self._preserve_parameter_order:
            arg = [(
                coercions.expect(roles.DMLColumnRole, k),
                coercions.expect(
                    roles.ExpressionElementRole,
                    v,
                    type_=NullType(),
                    is_crud=True,
                ),
            ) for k, v in arg]
            self._ordered_values = arg
        else:
            arg = {
                coercions.expect(roles.DMLColumnRole, k): coercions.expect(
                    roles.ExpressionElementRole,
                    v,
                    type_=NullType(),
                    is_crud=True,
                )
                for k, v in arg.items()
            }
            if self._values:
                self._values = self._values.union(arg)
            else:
                self._values = util.immutabledict(arg)