<commit_before>//
// $Id$
//
// Depot library - a Java relational persistence library
// Copyright (C) 2006-2008 <NAME> and <NAME>
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package com.samskivert.depot.impl;

import java.sql.Connection;
import java.sql.SQLException;

import java.util.Map;
import java.util.Set;

import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.annotation.FullTextIndex;
import com.samskivert.depot.expression.ColumnExp;
import com.samskivert.depot.operator.FullText;

import com.samskivert.depot.impl.clause.DeleteClause;
import com.samskivert.depot.impl.clause.DropIndexClause;
import com.samskivert.depot.impl.expression.DateFun.DatePart;
import com.samskivert.depot.impl.expression.DateFun.DateTruncate;
import com.samskivert.depot.impl.expression.DateFun.DatePart.Part;
import com.samskivert.depot.impl.expression.NumericalFun.Trunc;

import static com.samskivert.Log.log;

public class MySQLBuilder
    extends SQLBuilder
{
    public class MSBuildVisitor extends BuildVisitor
    {
        @Override public Void visit (FullText.Match match)
        {
            renderMatch(match.getDefinition());
            return null;
        }

        @Override public Void visit (FullText.Rank rank)
        {
            renderMatch(rank.getDefinition());
            return null;
        }

        @Override public Void visit (DeleteClause deleteClause)
        {
            _builder.append("delete from ");
            appendTableName(deleteClause.getPersistentClass());
            _builder.append(" ");

            // MySQL can't do DELETE FROM SomeTable AS T1, so we turn off abbreviations briefly.
            boolean savedFlag = _types.getUseTableAbbreviations();
            _types.setUseTableAbbreviations(false);
            try {
                deleteClause.getWhereClause().accept(this);
            } finally {
                _types.setUseTableAbbreviations(savedFlag);
            }
            return null;
        }

        @Override public Void visit (Trunc<?> exp)
        {
            return appendFunctionCall("truncate", exp.getArg());
        }

        @Override public Void visit (DatePart exp) {
            return appendFunctionCall(getDateFunction(exp.getPart()), exp.getArg());
        }

        @Override
        public Void visit (DateTruncate exp)
        {
            // exp.getTruncation() is currently always DAY
            _builder.append(" cast(");
            appendFunctionCall("date", exp.getArg());
            _builder.append(" as datetime)");
            return null;
        }

        protected String getDateFunction (Part part)
        {
            switch(part) {
            case DAY_OF_MONTH:
                return "dayofmonth";
            case DAY_OF_WEEK:
                return "dayofweek";
            case DAY_OF_YEAR:
                return "dayofyear";
            case HOUR:
                return "hour";
            case MINUTE:
                return "minute";
            case MONTH:
                return "month";
            case SECOND:
                return "second";
            case WEEK:
                return "week";
            case YEAR:
                return "year";
            case EPOCH:
                return "unix_timestamp";
            }
            throw new IllegalArgumentException("Unknown date part: " + part);
        }

        @Override
        public Void visit (DropIndexClause dropIndexClause)
        {
            // MySQL's indexes are scoped on the table, not on the database, and the
            // SQL syntax reflects it: DROP INDEX fooIx on fooTable
            _builder.append("drop index ");
            appendIdentifier(dropIndexClause.getName());
            _builder.append(" on ");
            appendTableName(dropIndexClause.getPersistentClass());
            return null;
        }

        protected MSBuildVisitor (DepotTypes types)
        {
            super(types, false);
        }

        @Override protected void appendTableName (Class<? extends PersistentRecord> type)
        {
            _builder.append(_types.getTableName(type));
        }

        @Override protected void appendTableAbbreviation (Class<? extends PersistentRecord> type)
        {
            _builder.append(_types.getTableAbbreviation(type));
        }

        @Override protected void appendIdentifier (String field)
        {
            _builder.append(field);
        }

        protected void renderMatch (FullText fullText)
        {
            _builder.append("match(");
            Class<? extends PersistentRecord> pClass = fullText.getPersistentClass();
            String[] fields = _types.getMarshaller(pClass).getFullTextIndex(
                    fullText.getName()).fields();
            for (int ii = 0; ii < fields.length; ii ++) {
                if (ii > 0) {
                    _builder.append(", ");
                }
                new ColumnExp<Object>(pClass, fields[ii]).accept(this);
            }
            _builder.append(") against (");
            bindValue(fullText.getQuery());
            _builder.append(" in boolean mode)");
        }
    }

    public MySQLBuilder (DepotTypes types)
    {
        super(types);
    }

    @Override
    public void getFtsIndexes (<commit_msg>We need to quote identifiers in MySQL so that we can handle columns with names like group.<commit_after>//
// $Id$
//
// Depot library - a Java relational persistence library
// Copyright (C) 2006-2008 <NAME> and <NAME>
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package com.samskivert.depot.impl;

import java.sql.Connection;
import java.sql.SQLException;

import java.util.Map;
import java.util.Set;

import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.annotation.FullTextIndex;
import com.samskivert.depot.expression.ColumnExp;
import com.samskivert.depot.operator.FullText;

import com.samskivert.depot.impl.clause.DeleteClause;
import com.samskivert.depot.impl.clause.DropIndexClause;
import com.samskivert.depot.impl.expression.DateFun.DatePart;
import com.samskivert.depot.impl.expression.DateFun.DateTruncate;
import com.samskivert.depot.impl.expression.DateFun.DatePart.Part;
import com.samskivert.depot.impl.expression.NumericalFun.Trunc;

import static com.samskivert.Log.log;

public class MySQLBuilder
    extends SQLBuilder
{
    public class MSBuildVisitor extends BuildVisitor
    {
        @Override public Void visit (FullText.Match match)
        {
            renderMatch(match.getDefinition());
            return null;
        }

        @Override public Void visit (FullText.Rank rank)
        {
            renderMatch(rank.getDefinition());
            return null;
        }

        @Override public Void visit (DeleteClause deleteClause)
        {
            _builder.append("delete from ");
            appendTableName(deleteClause.getPersistentClass());
            _builder.append(" ");

            // MySQL can't do DELETE FROM SomeTable AS T1, so we turn off abbreviations briefly.
            boolean savedFlag = _types.getUseTableAbbreviations();
            _types.setUseTableAbbreviations(false);
            try {
                deleteClause.getWhereClause().accept(this);
            } finally {
                _types.setUseTableAbbreviations(savedFlag);
            }
            return null;
        }

        @Override public Void visit (Trunc<?> exp)
        {
            return appendFunctionCall("truncate", exp.getArg());
        }

        @Override public Void visit (DatePart exp) {
            return appendFunctionCall(getDateFunction(exp.getPart()), exp.getArg());
        }

        @Override
        public Void visit (DateTruncate exp)
        {
            // exp.getTruncation() is currently always DAY
            _builder.append(" cast(");
            appendFunctionCall("date", exp.getArg());
            _builder.append(" as datetime)");
            return null;
        }

        protected String getDateFunction (Part part)
        {
            switch(part) {
            case DAY_OF_MONTH:
                return "dayofmonth";
            case DAY_OF_WEEK:
                return "dayofweek";
            case DAY_OF_YEAR:
                return "dayofyear";
            case HOUR:
                return "hour";
            case MINUTE:
                return "minute";
            case MONTH:
                return "month";
            case SECOND:
                return "second";
            case WEEK:
                return "week";
            case YEAR:
                return "year";
            case EPOCH:
                return "unix_timestamp";
            }
            throw new IllegalArgumentException("Unknown date part: " + part);
        }

        @Override
        public Void visit (DropIndexClause dropIndexClause)
        {
            // MySQL's indexes are scoped on the table, not on the database, and the
            // SQL syntax reflects it: DROP INDEX fooIx on fooTable
            _builder.append("drop index ");
            appendIdentifier(dropIndexClause.getName());
            _builder.append(" on ");
            appendTableName(dropIndexClause.getPersistentClass());
            return null;
        }

        protected MSBuildVisitor (DepotTypes types)
        {
            super(types, false);
        }

        @Override protected void appendTableName (Class<? extends PersistentRecord> type)
        {
            _builder.append(_types.getTableName(type));
        }

        @Override protected void appendTableAbbreviation (Class<? extends PersistentRecord> type)
        {
            _builder.append(_types.getTableAbbreviation(type));
        }

        @Override protected void appendIdentifier (String field)
        {
            _builder.append("`").append(field).append("`");
        }

        protected void renderMatch (FullText fullText)
        {
            _builder.append("match(");
            Class<? extends PersistentRecord> pClass = fullText.getPersistentClass();
            String[] fields = _types.getMarshaller(pClass).getFullTextIndex(
                    fullText.getName()).fields();
            for (int ii = 0; ii < fields.length; ii ++) {
                if (ii > 0) {
                    _builder.append(", ");
                }
                new ColumnExp<Object>(pClass, fields[ii]).accept(this);
            }
            _builder.append(") against (");
            bindValue(fullText.getQuery());
            _builder.append(" in boolean mode)");
        }
    }

    public MySQLBuilder (DepotTypes types)
    {
        super(types);
    }

    @Override
    public void getFtsIndexes (
{'fraction_non_alphanumeric': 0.09104514841606386, 'fraction_numerical': 0.004489897730107259, 'mean_word_length': 2.0373737373737373, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '4889836', 'n_tokens_mistral': 3239, 'n_tokens_neox': 3079, 'n_words': 872}