<commit_before>/*
 * DBeaver - Universal Database Manager
 * Copyright (C) 2010-2021 DBeaver Corp and others
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jkiss.dbeaver.ext.mssql.model;

import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.ext.mssql.SQLServerConstants;
import org.jkiss.dbeaver.ext.mssql.SQLServerUtils;
import org.jkiss.dbeaver.model.DBPDataKind;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCDatabaseMetaData;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCSession;
import org.jkiss.dbeaver.model.impl.jdbc.JDBCDataSource;
import org.jkiss.dbeaver.model.impl.jdbc.JDBCSQLDialect;
import org.jkiss.dbeaver.model.sql.SQLConstants;
import org.jkiss.dbeaver.model.sql.parser.rules.SQLMultiWordRule;
import org.jkiss.dbeaver.model.sql.parser.tokens.SQLTokenType;
import org.jkiss.dbeaver.model.struct.DBSTypedObject;
import org.jkiss.dbeaver.model.struct.rdb.DBSProcedure;
import org.jkiss.dbeaver.model.struct.rdb.DBSProcedureParameter;
import org.jkiss.dbeaver.model.text.parser.TPRule;
import org.jkiss.dbeaver.model.text.parser.TPRuleProvider;
import org.jkiss.dbeaver.model.text.parser.TPTokenDefault;
import org.jkiss.utils.ArrayUtils;
import org.jkiss.utils.CommonUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

public class SQLServerDialect extends JDBCSQLDialect implements TPRuleProvider {

    private static final String[][] TSQL_BEGIN_END_BLOCK = new String[][]{
        {SQLConstants.BLOCK_BEGIN, SQLConstants.BLOCK_END}
    };

    private static String[] SQLSERVER_EXTRA_KEYWORDS = new String[]{
        "TOP",
        "SYNONYM",
        "PERSISTED"
    };

    private static final String[][] SQLSERVER_QUOTE_STRINGS = {
            {"[", "]"},
            {"\"", "\""},
    };
    private static final String[][] SYBASE_LEGACY_QUOTE_STRINGS = {
        {"\"", "\""},
    };


    private static String[] EXEC_KEYWORDS =  { "CALL", "EXEC", "EXECUTE" };

    private static String[] PLAIN_TYPE_NAMES = {
        SQLServerConstants.TYPE_GEOGRAPHY,
        SQLServerConstants.TYPE_GEOMETRY,
        SQLServerConstants.TYPE_TIMESTAMP,
        SQLServerConstants.TYPE_IMAGE,
    };

    private static String[] SQLSERVER_FUNCTIONS_DATETIME = new String[]{
            "CURRENT_TIMEZONE",
            "DATEPART",
            "DATEADD",
            "DATEDIFF",
            "DATEDIFF_BIG",
            "DATEFROMPARTS",
            "DATENAME",
            "DATETIMEFROMPARTS",
            "EOMONTH",
            "GETDATE",
            "GETUTCDATE",
            "ISDATE",
            "SYSDATETIMEOFFSET",
            "SYSUTCDATETIME",
            "SMALLDATETIMEFROMPARTS",
            "SWITCHOFFSET",
            "TIMEFROMPARTS",
            "TODATETIMEOFFSET"
    };

    private JDBCDataSource dataSource;
    private boolean isSqlServer;

    public SQLServerDialect() {
        super("SQLServer", "sqlserver");
    }

    public void initDriverSettings(JDBCSession session, JDBCDataSource dataSource, JDBCDatabaseMetaData metaData) {
        super.initDriverSettings(session, dataSource, metaData);
        super.addSQLKeywords(Arrays.asList(SQLSERVER_EXTRA_KEYWORDS));
        this.dataSource = dataSource;
        this.isSqlServer = SQLServerUtils.isDriverSqlServer(dataSource.getContainer().getDriver());

        addFunctions(Arrays.asList(SQLSERVER_FUNCTIONS_DATETIME));
    }

    @NotNull
    @Override
    public String[] getScriptDelimiters() {
        return new String[]{";", "GO"};
    }

    @Override
    public boolean validIdentifierPart(char c, boolean quoted) {
        // SQL Server: All extra characters can be used in unquoted form
        return Character.isLetter(c) || Character.isDigit(c) || c == '_' || validCharacters.indexOf(c) != -1;

    }

    @NotNull
    @Override
    public String[] getExecuteKeywords() {
        return EXEC_KEYWORDS;
    }

    @NotNull
    @Override
    public String[] getParametersPrefixes() {
        return super.getParametersPrefixes();
        // Do not use @ as prefix - it can be used as a regular SQL construct (#5674)
        //return new String[] { "@" };
    }

    @Override
    public boolean isDelimiterAfterQuery() {
        return isSqlServer;
    }

    @Override
    public boolean needsDelimiterFor(String firstKeyword, String lastKeyword) {
        return SQLConstants.KEYWORD_MERGE.equalsIgnoreCase(firstKeyword) && lastKeyword != null;
    }

    @Override
    public boolean supportsSubqueries() {
        return true;
    }

    @Override
    public boolean supportsAliasInSelect() {
        return true;
    }

    @Override
    public boolean supportsNestedComments() {
        return true;
    }

    public String[][] getIdentifierQuoteStrings() {
        if (dataSource == null || (!isSqlServer && !dataSource.isServerVersionAtLeast(12, 6))) {
            // Old Sybase doesn't support square brackets - #7755
            return SYBASE_LEGACY_QUOTE_STRINGS;
        }
        return SQLSERVER_QUOTE_STRINGS;
    }

    @Override
    public String[][] getBlockBoundStrings() {
        return TSQL_BEGIN_END_BLOCK;
    }

    @NotNull
    @Override
    public MultiValueInsertMode getDefaultMultiValueInsertMode() {
        if (isSqlServer) {
            if (dataSource.isServerVersionAtLeast(SQLServerConstants.SQL_SERVER_2008_VERSION_MAJOR, 0)) {
                return MultiValueInsertMode.GROUP_ROWS;
            }
            return super.getDefaultMultiValueInsertMode();
        } else {
            return super.getDefaultMultiValueInsertMode();
        }
    }

    @Override
    public String getColumnTypeModifiers(@NotNull DBPDataSource dataSource, @NotNull DBSTypedObject column, @NotNull String typeName, @NotNull DBPDataKind dataKind) {
        if (dataKind == DBPDataKind.DATETIME) {
            if (SQLServerConstants.TYPE_DATETIME2.equalsIgnoreCase(typeName) ||
                    SQLServerConstants.TYPE_TIME.equalsIgnoreCase(typeName) ||
                    SQLServerConstants.TYPE_DATETIMEOFFSET.equalsIgnoreCase(typeName)) {
                Integer scale = column.getScale();
                if (scale != null && scale != 0) {
                    return "(" + scale + ')';
                }
            }
        } else if (dataKind == DBPDataKind.STRING || dataKind == DBPDataKind.BINARY) {
            switch (typeName) {
                case SQLServerConstants.TYPE_CHAR:
                case SQLServerConstants.TYPE_NCHAR:
                case SQLServerConstants.TYPE_VARCHAR:
                case SQLServerConstants.TYPE_NVARCHAR:
                case SQLServerConstants.TYPE_SQL_VARIANT:
                case SQLServerConstants.TYPE_VARBINARY:{
                    long maxLength = column.getMaxLength();
                    if (maxLength == 0) {
                        return null;
                    } else if (maxLength == -1 || maxLength > 8000) {
                        return "(MAX)";
                    } else {
                        return "(" + maxLength + ")";
                    }<commit_msg>#12965 change default scale value for date/time columns<commit_after>/*
 * DBeaver - Universal Database Manager
 * Copyright (C) 2010-2021 DBeaver Corp and others
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jkiss.dbeaver.ext.mssql.model;

import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.ext.mssql.SQLServerConstants;
import org.jkiss.dbeaver.ext.mssql.SQLServerUtils;
import org.jkiss.dbeaver.model.DBPDataKind;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCDatabaseMetaData;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCSession;
import org.jkiss.dbeaver.model.impl.jdbc.JDBCDataSource;
import org.jkiss.dbeaver.model.impl.jdbc.JDBCSQLDialect;
import org.jkiss.dbeaver.model.sql.SQLConstants;
import org.jkiss.dbeaver.model.sql.parser.rules.SQLMultiWordRule;
import org.jkiss.dbeaver.model.sql.parser.tokens.SQLTokenType;
import org.jkiss.dbeaver.model.struct.DBSTypedObject;
import org.jkiss.dbeaver.model.struct.rdb.DBSProcedure;
import org.jkiss.dbeaver.model.struct.rdb.DBSProcedureParameter;
import org.jkiss.dbeaver.model.text.parser.TPRule;
import org.jkiss.dbeaver.model.text.parser.TPRuleProvider;
import org.jkiss.dbeaver.model.text.parser.TPTokenDefault;
import org.jkiss.utils.ArrayUtils;
import org.jkiss.utils.CommonUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

public class SQLServerDialect extends JDBCSQLDialect implements TPRuleProvider {

    private static final String[][] TSQL_BEGIN_END_BLOCK = new String[][]{
        {SQLConstants.BLOCK_BEGIN, SQLConstants.BLOCK_END}
    };

    private static String[] SQLSERVER_EXTRA_KEYWORDS = new String[]{
        "TOP",
        "SYNONYM",
        "PERSISTED"
    };

    private static final String[][] SQLSERVER_QUOTE_STRINGS = {
            {"[", "]"},
            {"\"", "\""},
    };
    private static final String[][] SYBASE_LEGACY_QUOTE_STRINGS = {
        {"\"", "\""},
    };


    private static String[] EXEC_KEYWORDS =  { "CALL", "EXEC", "EXECUTE" };

    private static String[] PLAIN_TYPE_NAMES = {
        SQLServerConstants.TYPE_GEOGRAPHY,
        SQLServerConstants.TYPE_GEOMETRY,
        SQLServerConstants.TYPE_TIMESTAMP,
        SQLServerConstants.TYPE_IMAGE,
    };

    private static String[] SQLSERVER_FUNCTIONS_DATETIME = new String[]{
            "CURRENT_TIMEZONE",
            "DATEPART",
            "DATEADD",
            "DATEDIFF",
            "DATEDIFF_BIG",
            "DATEFROMPARTS",
            "DATENAME",
            "DATETIMEFROMPARTS",
            "EOMONTH",
            "GETDATE",
            "GETUTCDATE",
            "ISDATE",
            "SYSDATETIMEOFFSET",
            "SYSUTCDATETIME",
            "SMALLDATETIMEFROMPARTS",
            "SWITCHOFFSET",
            "TIMEFROMPARTS",
            "TODATETIMEOFFSET"
    };

    private JDBCDataSource dataSource;
    private boolean isSqlServer;

    public SQLServerDialect() {
        super("SQLServer", "sqlserver");
    }

    public void initDriverSettings(JDBCSession session, JDBCDataSource dataSource, JDBCDatabaseMetaData metaData) {
        super.initDriverSettings(session, dataSource, metaData);
        super.addSQLKeywords(Arrays.asList(SQLSERVER_EXTRA_KEYWORDS));
        this.dataSource = dataSource;
        this.isSqlServer = SQLServerUtils.isDriverSqlServer(dataSource.getContainer().getDriver());

        addFunctions(Arrays.asList(SQLSERVER_FUNCTIONS_DATETIME));
    }

    @NotNull
    @Override
    public String[] getScriptDelimiters() {
        return new String[]{";", "GO"};
    }

    @Override
    public boolean validIdentifierPart(char c, boolean quoted) {
        // SQL Server: All extra characters can be used in unquoted form
        return Character.isLetter(c) || Character.isDigit(c) || c == '_' || validCharacters.indexOf(c) != -1;

    }

    @NotNull
    @Override
    public String[] getExecuteKeywords() {
        return EXEC_KEYWORDS;
    }

    @NotNull
    @Override
    public String[] getParametersPrefixes() {
        return super.getParametersPrefixes();
        // Do not use @ as prefix - it can be used as a regular SQL construct (#5674)
        //return new String[] { "@" };
    }

    @Override
    public boolean isDelimiterAfterQuery() {
        return isSqlServer;
    }

    @Override
    public boolean needsDelimiterFor(String firstKeyword, String lastKeyword) {
        return SQLConstants.KEYWORD_MERGE.equalsIgnoreCase(firstKeyword) && lastKeyword != null;
    }

    @Override
    public boolean supportsSubqueries() {
        return true;
    }

    @Override
    public boolean supportsAliasInSelect() {
        return true;
    }

    @Override
    public boolean supportsNestedComments() {
        return true;
    }

    public String[][] getIdentifierQuoteStrings() {
        if (dataSource == null || (!isSqlServer && !dataSource.isServerVersionAtLeast(12, 6))) {
            // Old Sybase doesn't support square brackets - #7755
            return SYBASE_LEGACY_QUOTE_STRINGS;
        }
        return SQLSERVER_QUOTE_STRINGS;
    }

    @Override
    public String[][] getBlockBoundStrings() {
        return TSQL_BEGIN_END_BLOCK;
    }

    @NotNull
    @Override
    public MultiValueInsertMode getDefaultMultiValueInsertMode() {
        if (isSqlServer) {
            if (dataSource.isServerVersionAtLeast(SQLServerConstants.SQL_SERVER_2008_VERSION_MAJOR, 0)) {
                return MultiValueInsertMode.GROUP_ROWS;
            }
            return super.getDefaultMultiValueInsertMode();
        } else {
            return super.getDefaultMultiValueInsertMode();
        }
    }

    @Override
    public String getColumnTypeModifiers(@NotNull DBPDataSource dataSource, @NotNull DBSTypedObject column, @NotNull String typeName, @NotNull DBPDataKind dataKind) {
        if (dataKind == DBPDataKind.DATETIME) {
            if (SQLServerConstants.TYPE_DATETIME2.equalsIgnoreCase(typeName) ||
                    SQLServerConstants.TYPE_TIME.equalsIgnoreCase(typeName) ||
                    SQLServerConstants.TYPE_DATETIMEOFFSET.equalsIgnoreCase(typeName)) {
                Integer scale = column.getScale();
                if (scale != null && scale >= 0 && scale < 7) {
                    return "(" + scale + ')';
                }
            }
        } else if (dataKind == DBPDataKind.STRING || dataKind == DBPDataKind.BINARY) {
            switch (typeName) {
                case SQLServerConstants.TYPE_CHAR:
                case SQLServerConstants.TYPE_NCHAR:
                case SQLServerConstants.TYPE_VARCHAR:
                case SQLServerConstants.TYPE_NVARCHAR:
                case SQLServerConstants.TYPE_SQL_VARIANT:
                case SQLServerConstants.TYPE_VARBINARY:{
                    long maxLength = column.getMaxLength();
                    if (maxLength == 0) {
                        return null;
                    } else if (maxLength == -1 || maxLength > 8000) {
                        return "(MAX)";
                    } else {
                        return "(" + maxLength + ")";
                    }
{'fraction_non_alphanumeric': 0.09861715250275921, 'fraction_numerical': 0.005193793416866844, 'mean_word_length': 2.635591220202974, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6966147', 'n_tokens_mistral': 4618, 'n_tokens_neox': 4412, 'n_words': 927}