def query(self, query, table_name=None, decode_geom=False, is_select=None):
        """Pull the result from an arbitrary SQL SELECT query from a CARTO account
        into a pandas DataFrame. This is the default behavior, when `is_select=True`

        Can also be used to perform database operations (creating/dropping tables,
        adding columns, updates, etc.). In this case, you have to explicitly
        specify `is_select=False`

        This method is a helper for the `CartoContext.fetch` and `CartoContext.execute`
        methods. We strongly encourage you to use any of those methods depending on the
        type of query you want to run. If you want to get the results of a `SELECT` query
        into a pandas DataFrame, then use `CartoContext.fetch`. For any other query that
        performs an operation into the CARTO database, use `CartoContext.execute`

        Args:
            query (str): Query to run against CARTO user database. This data
              will then be converted into a pandas DataFrame.
            table_name (str, optional): If set (and `is_select=True`), this will create a new
              table in the user's CARTO account that is the result of the SELECT
              query provided. Defaults to None (no table created).
            decode_geom (bool, optional): Decodes CARTO's geometries into a
              `Shapely <https://github.com/Toblerity/Shapely>`__
              object that can be used, for example, in `GeoPandas
              <http://geopandas.org/>`__. It only works for SELECT queries when `is_select=True`
            is_select (bool, optional): This argument has to be set depending on the query
              performed. True for SELECT queries, False for any other query.
              For the case of a SELECT SQL query (`is_select=True`) the result will be stored into a
              pandas DataFrame.
              When an arbitrary SQL query (`is_select=False`) it will perform a database
              operation (UPDATE, DROP, INSERT, etc.)
              By default `is_select=None` that means that the method will return a dataframe if
              the `query` starts with a `select` clause, otherwise it will just execute the query
              and return `None`

        Returns:
            pandas.DataFrame: When `is_select=True` and the query is actually a SELECT query
            this method returns a pandas DataFrame representation of query supplied otherwise
            returns None.
            Pandas data types are inferred from PostgreSQL data types.
            In the case of PostgreSQL date types, dates are attempted to be
            converted, but on failure a data type 'object' is used.

        Raises:
            CartoException: If there's any error when executing the query

        Examples:
            Query a table in CARTO and write a new table that is result of
            query. This query gets the 10 highest values from a table and
            returns a dataframe, as well as creating a new table called
            'top_ten' in the CARTO account.

            .. code:: python

                topten_df = cc.query(
                    '''
                      SELECT * FROM
                      my_table
                      ORDER BY value_column DESC
                      LIMIT 10
                    ''',
                    table_name='top_ten'
                )

            This query joins points to polygons based on intersection, and
            aggregates by summing the values of the points in each polygon. The
            query returns a dataframe, with a geometry column that contains
            polygons and also creates a new table called
            'points_aggregated_to_polygons' in the CARTO account.

            .. code:: python

                points_aggregated_to_polygons = cc.query(
                    '''
                      SELECT polygons.*, sum(points.values)
                      FROM polygons JOIN points
                      ON ST_Intersects(points.the_geom, polygons.the_geom)
                      GROUP BY polygons.the_geom, polygons.cartodb_id
                    ''',
                    table_name='points_aggregated_to_polygons',
                    decode_geom=True
                )

            Drops `my_table`

            .. code:: python

                cc.query(
                    '''
                      DROP TABLE my_table
                    '''
                )

            Updates the column `my_column` in the table `my_table`

            .. code:: python

                cc.query(
                    '''
                      UPDATE my_table SET my_column = 1
                    '''
                )

        """
        dataframe = None

        is_select_query = is_select or (is_select is None and query.strip().lower().startswith('select'))
        if is_select_query:
            if table_name:
                dataset = Dataset.create_from_query(self, query, table_name)
                dataframe = dataset.download(decode_geom=decode_geom)
            else:
                dataframe = self.fetch(query, decode_geom=decode_geom)
        else:
            self.execute(query)

        return dataframe
Pull the result from an arbitrary SQL SELECT query from a CARTO account
        into a pandas DataFrame. This is the default behavior, when `is_select=True`

        Can also be used to perform database operations (creating/dropping tables,
        adding columns, updates, etc.). In this case, you have to explicitly
        specify `is_select=False`

        This method is a helper for the `CartoContext.fetch` and `CartoContext.execute`
        methods. We strongly encourage you to use any of those methods depending on the
        type of query you want to run. If you want to get the results of a `SELECT` query
        into a pandas DataFrame, then use `CartoContext.fetch`. For any other query that
        performs an operation into the CARTO database, use `CartoContext.execute`

        Args:
            query (str): Query to run against CARTO user database. This data
              will then be converted into a pandas DataFrame.
            table_name (str, optional): If set (and `is_select=True`), this will create a new
              table in the user's CARTO account that is the result of the SELECT
              query provided. Defaults to None (no table created).
            decode_geom (bool, optional): Decodes CARTO's geometries into a
              `Shapely <https://github.com/Toblerity/Shapely>`__
              object that can be used, for example, in `GeoPandas
              <http://geopandas.org/>`__. It only works for SELECT queries when `is_select=True`
            is_select (bool, optional): This argument has to be set depending on the query
              performed. True for SELECT queries, False for any other query.
              For the case of a SELECT SQL query (`is_select=True`) the result will be stored into a
              pandas DataFrame.
              When an arbitrary SQL query (`is_select=False`) it will perform a database
              operation (UPDATE, DROP, INSERT, etc.)
              By default `is_select=None` that means that the method will return a dataframe if
              the `query` starts with a `select` clause, otherwise it will just execute the query
              and return `None`

        Returns:
            pandas.DataFrame: When `is_select=True` and the query is actually a SELECT query
            this method returns a pandas DataFrame representation of query supplied otherwise
            returns None.
            Pandas data types are inferred from PostgreSQL data types.
            In the case of PostgreSQL date types, dates are attempted to be
            converted, but on failure a data type 'object' is used.

        Raises:
            CartoException: If there's any error when executing the query

        Examples:
            Query a table in CARTO and write a new table that is result of
            query. This query gets the 10 highest values from a table and
            returns a dataframe, as well as creating a new table called
            'top_ten' in the CARTO account.

            .. code:: python

                topten_df = cc.query(
                    '''
                      SELECT * FROM
                      my_table
                      ORDER BY value_column DESC
                      LIMIT 10
                    ''',
                    table_name='top_ten'
                )

            This query joins points to polygons based on intersection, and
            aggregates by summing the values of the points in each polygon. The
            query returns a dataframe, with a geometry column that contains
            polygons and also creates a new table called
            'points_aggregated_to_polygons' in the CARTO account.

            .. code:: python

                points_aggregated_to_polygons = cc.query(
                    '''
                      SELECT polygons.*, sum(points.values)
                      FROM polygons JOIN points
                      ON ST_Intersects(points.the_geom, polygons.the_geom)
                      GROUP BY polygons.the_geom, polygons.cartodb_id
                    ''',
                    table_name='points_aggregated_to_polygons',
                    decode_geom=True
                )

            Drops `my_table`

            .. code:: python

                cc.query(
                    '''
                      DROP TABLE my_table
                    '''
                )

            Updates the column `my_column` in the table `my_table`

            .. code:: python

                cc.query(
                    '''
                      UPDATE my_table SET my_column = 1
                    '''
                )