<commit_before>from __future__ import absolute_import, unicode_literals

import datetime
import django
from django.conf import settings
from django.db.backends import BaseDatabaseOperations

try:
    from django.utils.encoding import smart_text
except:
    from django.utils.encoding import smart_unicode as smart_text

try:
    import pytz
except ImportError:
    pytz = None

from django.utils import six, timezone

from . import fields as mssql_fields

class DatabaseOperations(BaseDatabaseOperations):
    compiler_module = "sqlserver_ado.compiler"
    
    _convert_values_map = {
        # custom fields
        'DateTimeOffsetField':  mssql_fields.DateTimeOffsetField(),
        'LegacyDateField':      mssql_fields.LegacyDateField(),
        'LegacyDateTimeField':  mssql_fields.LegacyDateTimeField(),
        'LegacyTimeField':      mssql_fields.LegacyTimeField(),
        'NewDateField':         mssql_fields.DateField(),
        'NewDateTimeField':     mssql_fields.DateTimeField(),
        'NewTimeField':         mssql_fields.TimeField(),
    }

    def __init__(self, *args, **kwargs):
        super(DatabaseOperations, self).__init__(*args, **kwargs)

        if self.connection.use_legacy_date_fields:
            self.value_to_db_datetime = self._legacy_value_to_db_datetime
            self.value_to_db_time = self._legacy_value_to_db_time

            self._convert_values_map.update({
                'DateField':        self._convert_values_map['LegacyDateField'],
                'DateTimeField':    self._convert_values_map['LegacyDateTimeField'],
                'TimeField':        self._convert_values_map['LegacyTimeField'],
            })
        else:
            self.value_to_db_datetime = self._new_value_to_db_datetime
            self.value_to_db_time = self._new_value_to_db_time

            self._convert_values_map.update({
                'DateField':        self._convert_values_map['NewDateField'],
                'DateTimeField':    self._convert_values_map['NewDateTimeField'],
                'TimeField':        self._convert_values_map['NewTimeField'],
            })

    def cache_key_culling_sql(self):
        return """
            SELECT [cache_key]
              FROM (SELECT [cache_key], ROW_NUMBER() OVER (ORDER BY [cache_key]) AS [rank] FROM %s) AS [RankedCache]
             WHERE [rank] = %%s + 1
        """

    def date_extract_sql(self, lookup_type, field_name):
        field_name = self.quote_name(field_name)
        if lookup_type == 'week_day':
            lookup_type = 'weekday'
        return 'DATEPART(%s, %s)' % (lookup_type, field_name)

    def date_interval_sql(self, sql, connector, timedelta):
        """
        implements the interval functionality for expressions
        format for SQL Server.
        """
        sign = 1 if connector == '+' else -1
        if timedelta.seconds or timedelta.microseconds:
            # assume the underlying datatype supports seconds/microseconds
            seconds = ((timedelta.days * 86400) + timedelta.seconds) * sign
            out = sql
            if seconds:
                out = 'DATEADD(SECOND, {0}, {1})'.format(seconds, sql)
            if timedelta.microseconds:
                # DATEADD with datetime doesn't support ms, must cast up
                out = 'DATEADD(MICROSECOND, {ms}, CAST({sql} as datetime2))'.format(
                    ms=timedelta.microseconds * sign,
                    sql=out,
                )
        else:
            # Only days in the delta, assume underlying datatype can DATEADD with days
            out = 'DATEADD(DAY, {0}, {1})'.format(timedelta.days * sign, sql)
        return out

    def date_trunc_sql(self, lookup_type, field_name):
        return "DATEADD(%s, DATEDIFF(%s, 0, %s), 0)" % (lookup_type, lookup_type, field_name)


    def _switch_tz_offset(self, field_name, tzname):
        field_name = self.quote_name(field_name)
        if settings.USE_TZ:
            if pytz is None:
                from django.core.exceptions import ImproperlyConfigured
                raise ImproperlyConfigured("This query requires pytz, "
                                           "but it isn't installed.")
            tz = pytz.timezone(tzname)
            td = tz.utcoffset(datetime.datetime(2000, 1, 1))

            def total_seconds(td):
                if hasattr(td, 'total_seconds'):
                    return td.total_seconds()
                else:
                    return td.days * 24 * 60 * 60 + td.seconds

            total_minutes = total_seconds(td) // 60
            hours, minutes = divmod(total_minutes, 60)
            tzoffset = "%+03d:%02d" % (hours, minutes)
            field_name = "CAST(SWITCHOFFSET(TODATETIMEOFFSET(%s, '+00:00'), '%s') AS DATETIME2)" % (field_name, tzoffset)
        return field_name

    def datetime_extract_sql(self, lookup_type, field_name, tzname):
        """
        Given a lookup_type of 'year', 'month', 'day', 'hour', 'minute' or
        'second', returns the SQL that extracts a value from the given
        datetime field field_name, and a tuple of parameters.
        """
        if lookup_type == 'week_day':
            lookup_type = 'weekday'
        return 'DATEPART({0}, {1})'.format(
            lookup_type,
            self.__switch_tz_offset(field_name, tzname),
            ), []

    def datetime_trunc_sql(self, lookup_type, field_name, tzname):
        """
        Given a lookup_type of 'year', 'month', 'day', 'hour', 'minute' or
        'second', returns the SQL that truncates the given datetime field
        field_name to a datetime object with only the given specificity, and
        a tuple of parameters.
        """
        field_name = self._switch_tz_offset(field_name, tzname)
        reference_date = '0' # 1900-01-01
        if lookup_type in ['minute', 'second']:
            # Prevent DATEDIFF overflow by using the first day of the year as
            # the reference point. Only using for minute and second to avoid any
            # potential performance hit for queries against very large datasets.
            reference_date = "CONVERT(datetime2, CONVERT(char(4), {field_name}, 112) + '0101', 112)".format(
                field_name=field_name,
            )
        sql = "DATEADD({lookup}, DATEDIFF({lookup}, {reference_date}, {field_name}), {reference_date})".format(
            lookup=lookup_type,
            field_name=field_name,
            reference_date=reference_date,
        )
        return sql, []

    def last_insert_id(self, cursor, table_name, pk_name):
        """
        Fetch the last inserted ID by executing another query.
        """
        # IDENT_CURRENT   returns the last identity value generated for a 
        #                 specific table in any session and any scope.
        # http://msdn.microsoft.com/en-us/library/ms175098.aspx
        cursor.execute("SELECT CAST(IDENT_CURRENT(%s) as bigint)", [self.quote_name(table_name)])
        return cursor.fetchone()[0]<commit_msg>Renamed _switch_tz_offset to _switch_tz_offset_sql and documented<commit_after>from __future__ import absolute_import, unicode_literals

import datetime
import django
from django.conf import settings
from django.db.backends import BaseDatabaseOperations

try:
    from django.utils.encoding import smart_text
except:
    from django.utils.encoding import smart_unicode as smart_text

try:
    import pytz
except ImportError:
    pytz = None

from django.utils import six, timezone

from . import fields as mssql_fields

class DatabaseOperations(BaseDatabaseOperations):
    compiler_module = "sqlserver_ado.compiler"
    
    _convert_values_map = {
        # custom fields
        'DateTimeOffsetField':  mssql_fields.DateTimeOffsetField(),
        'LegacyDateField':      mssql_fields.LegacyDateField(),
        'LegacyDateTimeField':  mssql_fields.LegacyDateTimeField(),
        'LegacyTimeField':      mssql_fields.LegacyTimeField(),
        'NewDateField':         mssql_fields.DateField(),
        'NewDateTimeField':     mssql_fields.DateTimeField(),
        'NewTimeField':         mssql_fields.TimeField(),
    }

    def __init__(self, *args, **kwargs):
        super(DatabaseOperations, self).__init__(*args, **kwargs)

        if self.connection.use_legacy_date_fields:
            self.value_to_db_datetime = self._legacy_value_to_db_datetime
            self.value_to_db_time = self._legacy_value_to_db_time

            self._convert_values_map.update({
                'DateField':        self._convert_values_map['LegacyDateField'],
                'DateTimeField':    self._convert_values_map['LegacyDateTimeField'],
                'TimeField':        self._convert_values_map['LegacyTimeField'],
            })
        else:
            self.value_to_db_datetime = self._new_value_to_db_datetime
            self.value_to_db_time = self._new_value_to_db_time

            self._convert_values_map.update({
                'DateField':        self._convert_values_map['NewDateField'],
                'DateTimeField':    self._convert_values_map['NewDateTimeField'],
                'TimeField':        self._convert_values_map['NewTimeField'],
            })

    def cache_key_culling_sql(self):
        return """
            SELECT [cache_key]
              FROM (SELECT [cache_key], ROW_NUMBER() OVER (ORDER BY [cache_key]) AS [rank] FROM %s) AS [RankedCache]
             WHERE [rank] = %%s + 1
        """

    def date_extract_sql(self, lookup_type, field_name):
        field_name = self.quote_name(field_name)
        if lookup_type == 'week_day':
            lookup_type = 'weekday'
        return 'DATEPART(%s, %s)' % (lookup_type, field_name)

    def date_interval_sql(self, sql, connector, timedelta):
        """
        implements the interval functionality for expressions
        format for SQL Server.
        """
        sign = 1 if connector == '+' else -1
        if timedelta.seconds or timedelta.microseconds:
            # assume the underlying datatype supports seconds/microseconds
            seconds = ((timedelta.days * 86400) + timedelta.seconds) * sign
            out = sql
            if seconds:
                out = 'DATEADD(SECOND, {0}, {1})'.format(seconds, sql)
            if timedelta.microseconds:
                # DATEADD with datetime doesn't support ms, must cast up
                out = 'DATEADD(MICROSECOND, {ms}, CAST({sql} as datetime2))'.format(
                    ms=timedelta.microseconds * sign,
                    sql=out,
                )
        else:
            # Only days in the delta, assume underlying datatype can DATEADD with days
            out = 'DATEADD(DAY, {0}, {1})'.format(timedelta.days * sign, sql)
        return out

    def date_trunc_sql(self, lookup_type, field_name):
        return "DATEADD(%s, DATEDIFF(%s, 0, %s), 0)" % (lookup_type, lookup_type, field_name)


    def _switch_tz_offset_sql(self, field_name, tzname):
        """
        Returns the SQL that will convert field_name to UTC from tzname.
        """
        field_name = self.quote_name(field_name)
        if settings.USE_TZ:
            if pytz is None:
                from django.core.exceptions import ImproperlyConfigured
                raise ImproperlyConfigured("This query requires pytz, "
                                           "but it isn't installed.")
            tz = pytz.timezone(tzname)
            td = tz.utcoffset(datetime.datetime(2000, 1, 1))

            def total_seconds(td):
                if hasattr(td, 'total_seconds'):
                    return td.total_seconds()
                else:
                    return td.days * 24 * 60 * 60 + td.seconds

            total_minutes = total_seconds(td) // 60
            hours, minutes = divmod(total_minutes, 60)
            tzoffset = "%+03d:%02d" % (hours, minutes)
            field_name = "CAST(SWITCHOFFSET(TODATETIMEOFFSET(%s, '+00:00'), '%s') AS DATETIME2)" % (field_name, tzoffset)
        return field_name

    def datetime_extract_sql(self, lookup_type, field_name, tzname):
        """
        Given a lookup_type of 'year', 'month', 'day', 'hour', 'minute' or
        'second', returns the SQL that extracts a value from the given
        datetime field field_name, and a tuple of parameters.
        """
        if lookup_type == 'week_day':
            lookup_type = 'weekday'
        return 'DATEPART({0}, {1})'.format(
            lookup_type,
            self._switch_tz_offset_sql(field_name, tzname),
            ), []

    def datetime_trunc_sql(self, lookup_type, field_name, tzname):
        """
        Given a lookup_type of 'year', 'month', 'day', 'hour', 'minute' or
        'second', returns the SQL that truncates the given datetime field
        field_name to a datetime object with only the given specificity, and
        a tuple of parameters.
        """
        field_name = self._switch_tz_offset_sql(field_name, tzname)
        reference_date = '0' # 1900-01-01
        if lookup_type in ['minute', 'second']:
            # Prevent DATEDIFF overflow by using the first day of the year as
            # the reference point. Only using for minute and second to avoid any
            # potential performance hit for queries against very large datasets.
            reference_date = "CONVERT(datetime2, CONVERT(char(4), {field_name}, 112) + '0101', 112)".format(
                field_name=field_name,
            )
        sql = "DATEADD({lookup}, DATEDIFF({lookup}, {reference_date}, {field_name}), {reference_date})".format(
            lookup=lookup_type,
            field_name=field_name,
            reference_date=reference_date,
        )
        return sql, []

    def last_insert_id(self, cursor, table_name, pk_name):
        """
        Fetch the last inserted ID by executing another query.
        """
        # IDENT_CURRENT   returns the last identity value generated for a 
        #                 specific table in any session and any scope.
        # http://msdn.microsoft.com/en-us/library/ms175098.aspx
        cursor.execute("SELECT CAST(IDENT_CURRENT(%s) as bigint)", [self.quote_name(table_name)])
        return cursor.fetchone()[0]
{'fraction_non_alphanumeric': 0.09670345217883418, 'fraction_numerical': 0.009903791737408036, 'mean_word_length': 2.3169873298920693, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4524860', 'n_tokens_mistral': 4175, 'n_tokens_neox': 3932, 'n_words': 995}