示例#1
0
        private static SqlString GetWhereJoinFragment(IJoinable persister, string tableAlias)
        {
            SqlString whereJoinFragment = persister.WhereJoinFragment(tableAlias, true, false);

            if (whereJoinFragment == null)
            {
                whereJoinFragment = SqlString.Empty;
            }
            else
            {
                whereJoinFragment = whereJoinFragment.Trim();
                if (whereJoinFragment.StartsWithCaseInsensitive("and "))
                {
                    whereJoinFragment = whereJoinFragment.Substring(4);
                }
            }
            return(whereJoinFragment);
        }
示例#2
0
        /// <inheritdoc />
        public EntityInfo Extract(DbCommand command, SqlString sqlString)
        {
            if (!sqlString.StartsWithCaseInsensitive("INSERT INTO"))
            {
                return(null);
            }

            var parser = new SqlTokenizer(new SqlString(command.CommandText));

            using (var enumerator = parser.GetEnumerator())
            {
                ReadToTablePath(enumerator);
                var tablePath = ReadTablePath(enumerator);
                if (tablePath == null)
                {
                    return(null);
                }
                var columns = ReadColumns(enumerator);
                if (columns == null)
                {
                    return(null);
                }
                ReadToValues(enumerator);
                var parameters = ReadParameters(enumerator);
                if (parameters == null)
                {
                    return(null);
                }

                if (columns.Length != parameters.Length)
                {
                    return(null);
                }

                return(new EntityInfo()
                {
                    State = EntityState.Added,
                    TablePath = tablePath,
                    Values = ExtractorHelper.CreateValues(columns, parameters, command)
                });
            }
        }
示例#3
0
        public override SqlString OnPrepareStatement(SqlString sql)
        {
            if (sql.StartsWithCaseInsensitive("SELECT"))
            {
                var lists = sql.ToString().Split().ToList();
                var from  = lists.FirstOrDefault(p => p.Trim().Equals("FROM", StringComparison.OrdinalIgnoreCase));
                var index = from != null?lists.IndexOf(from) : -1;

                if (index == -1)
                {
                    return(sql);
                }

                // Add hint with nolock to sql string
                lists.Insert(lists.IndexOf(from) + 3, "WITH (NOLOCK)");

                sql = SqlString.Parse(string.Join(" ", lists));
            }
            return(sql);
        }
    public override SqlString OnPrepareStatement(SqlString sql)
    {
        //var log = new StringBuilder();
        //log.Append(sql.ToString());
        //log.AppendLine();

        // Modify the sql to add hints
        if (sql.StartsWithCaseInsensitive("select"))
        {
            var parts     = sql.ToString().Split().ToList();
            var fromItem  = parts.FirstOrDefault(p => p.Trim().Equals("from", StringComparison.OrdinalIgnoreCase));
            int fromIndex = fromItem != null?parts.IndexOf(fromItem) : -1;

            var whereItem  = parts.FirstOrDefault(p => p.Trim().Equals("where", StringComparison.OrdinalIgnoreCase));
            int whereIndex = whereItem != null?parts.IndexOf(whereItem) : parts.Count;

            if (fromIndex == -1)
            {
                return(sql);
            }

            parts.Insert(parts.IndexOf(fromItem) + 3, "WITH (NOLOCK)");
            for (int i = fromIndex; i < whereIndex; i++)
            {
                if (parts[i - 1].Equals(","))
                {
                    parts.Insert(i + 3, "WITH (NOLOCK)");
                    i += 3;
                }
                if (parts[i].Trim().Equals("on", StringComparison.OrdinalIgnoreCase))
                {
                    parts[i] = "WITH (NOLOCK) on";
                }
            }
            // MUST use SqlString.Parse() method instead of new SqlString()
            sql = SqlString.Parse(string.Join(" ", parts));
        }

        //log.Append(sql);
        return(sql);
    }
        /// <inheritdoc />
        public EntityInfo Extract(DbCommand command, SqlString sqlString)
        {
            if (!sqlString.StartsWithCaseInsensitive("UPDATE"))
            {
                return(null);
            }

            var parser = new SqlTokenizer(new SqlString(command.CommandText));

            using (var enumerator = parser.GetEnumerator())
            {
                ReadToTablePath(enumerator);
                var tablePath = ReadTablePath(enumerator);
                if (tablePath == null)
                {
                    return(null);
                }
                var set = ReadSet(enumerator);
                if (set == null)
                {
                    return(null);
                }
                var where = ReadWhere(enumerator);
                if (where == null)
                {
                    return(null);
                }

                var setValues   = ExtractorHelper.CreateValues(set.Item1, set.Item2, command);
                var whereValues = ExtractorHelper.CreateValues(where.Item1, where.Item2, command);

                return(new EntityInfo()
                {
                    State = EntityState.Modified,
                    TablePath = tablePath,
                    Values = ExtractorHelper.Union(whereValues, setValues),
                    UpdatedKey = ExtractorHelper.Intersect(setValues, whereValues)
                });
            }
        }
        /// <summary>
        /// For a <code>DISTINCT</code> query, identify the columns for the <code>ROW_NUMBER() OVER(ORDER BY ...)</code> expression.
        /// </summary>
        /// <param name="columnToAlias"></param>
        /// <param name="sortExpressions"></param>
        /// <param name="result"></param>
        /// <remarks>
        /// For a paged <code>DISTINCT</code> query, the columns on which ordering will be performed are returned by a sub-query. Therefore the
        /// columns in the <code>ROW_NUMBER() OVER(ORDER BY ...)</code> expression need to use the aliased column name from the subquery,
        /// prefixed by the subquery alias, <code>q_</code>.
        /// </remarks>
        private static void AppendSortExpressionsForDistinct(Dictionary <SqlString, SqlString> columnToAlias, SqlString[] sortExpressions, SqlStringBuilder result)
        {
            for (int i = 0; i < sortExpressions.Length; i++)
            {
                if (i > 0)
                {
                    result.Add(", ");
                }

                SqlString sortExpression = RemoveSortOrderDirection(sortExpressions[i]);

                if (sortExpression.StartsWithCaseInsensitive("CURRENT_TIMESTAMP"))
                {
                    result.Add(sortExpression);
                }

                else if (columnToAlias.ContainsKey(sortExpression))
                {
                    result.Add("q_.");
                    result.Add(columnToAlias[sortExpression]);
                }
                else if (columnToAlias.ContainsValue(sortExpression))                 // When a distinct query is paged the sortexpressions could already be aliased.
                {
                    result.Add("q_.");
                    result.Add(sortExpression);
                }
                else
                {
                    throw new HibernateException(
                              "The dialect was unable to perform paging of a statement that requires distinct results, and "
                              + "is ordered by a column that is not included in the result set of the query.");
                }

                if (sortExpressions[i].Trim().EndsWithCaseInsensitive("desc"))
                {
                    result.Add(" DESC");
                }
            }
        }
        // based on https://stackoverflow.com/a/39518098/2669614
        public override SqlString OnPrepareStatement(SqlString sql)
        {
            // Modify the sql to add hints
            if (sql.StartsWithCaseInsensitive("select"))
            {
                var parts     = sql.ToString().Split().ToList();
                var fromItem  = parts.FirstOrDefault(p => p.Trim().Equals("from", StringComparison.OrdinalIgnoreCase));
                int fromIndex = fromItem != null?parts.IndexOf(fromItem) : -1;

                var whereItem  = parts.FirstOrDefault(p => p.Trim().Equals("where", StringComparison.OrdinalIgnoreCase));
                int whereIndex = whereItem != null?parts.IndexOf(whereItem) : parts.Count;

                if (fromIndex == -1)
                {
                    return(sql);
                }

                foreach (var tableName in TableNames)
                {
                    // set NOLOCK for each one of these tables
                    var tableItem = parts
                                    .FirstOrDefault(p => p.Trim()
                                                    .Equals(tableName, StringComparison.OrdinalIgnoreCase));
                    if (tableItem != null)
                    {
                        // the table is involved in this statement
                        var tableIndex = parts.IndexOf(tableItem);
                        // recompute whereIndex in case we added stuff to parts
                        whereIndex = whereItem != null?parts.IndexOf(whereItem) : parts.Count;

                        if (tableIndex > fromIndex && tableIndex < whereIndex)   // sanity check
                        // if before the table name we have "," or "FROM", this is not a join, but rather
                        // something like "FROM tableName alias ..."
                        // we can insert "WITH (NOLOCK)" after that
                        {
                            if (tableIndex == fromIndex + 1 ||
                                parts[tableIndex - 1].Equals(","))
                            {
                                parts.Insert(tableIndex + 2, "WITH (NOLOCK)");
                            }
                            else
                            {
                                // probably doing a join, so edit the next "on" and make it
                                // "WITH (NOLOCK) on"
                                for (int i = tableIndex + 1; i < whereIndex; i++)
                                {
                                    if (parts[i].Trim().Equals("on", StringComparison.OrdinalIgnoreCase))
                                    {
                                        parts[i] = "WITH (NOLOCK) on";
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }

                // MUST use SqlString.Parse() method instead of new SqlString()
                sql = SqlString.Parse(string.Join(" ", parts));
            }

            return(sql);
        }
示例#8
0
        public void AddWhereFragment(
            JoinFragment joinFragment,
            SqlString whereFragment,
            QueryNode query,
            FromElement fromElement,
            HqlSqlWalker hqlSqlWalker)
        {
            if (whereFragment == null)
            {
                return;
            }

            if (!fromElement.UseWhereFragment && !joinFragment.HasThetaJoins)
            {
                return;
            }

            whereFragment = whereFragment.Trim();
            if (StringHelper.IsEmpty(whereFragment.ToString()))
            {
                return;
            }

            // Forcefully remove leading ands from where fragments; the grammar will
            // handle adding them
            if (whereFragment.StartsWithCaseInsensitive("and"))
            {
                whereFragment = whereFragment.Substring(4);
            }

            log.Debug("Using unprocessed WHERE-fragment [" + whereFragment + "]");

            SqlFragment fragment = (SqlFragment)Create(HqlSqlWalker.SQL_TOKEN, whereFragment.ToString());

            fragment.SetJoinFragment(joinFragment);
            fragment.FromElement = fromElement;

            if (fromElement.IndexCollectionSelectorParamSpec != null)
            {
                fragment.AddEmbeddedParameter(fromElement.IndexCollectionSelectorParamSpec);
                fromElement.IndexCollectionSelectorParamSpec = null;
            }

            if (hqlSqlWalker.IsFilter())
            {
                //if (whereFragment.IndexOfCaseInsensitive("?") >= 0)
                if (whereFragment.ToString().IndexOf("?") >= 0)
                {
                    IType collectionFilterKeyType = hqlSqlWalker.SessionFactoryHelper
                                                    .RequireQueryableCollection(hqlSqlWalker.CollectionFilterRole)
                                                    .KeyType;
                    CollectionFilterKeyParameterSpecification paramSpec = new CollectionFilterKeyParameterSpecification(
                        hqlSqlWalker.CollectionFilterRole,
                        collectionFilterKeyType,
                        0
                        );
                    fragment.AddEmbeddedParameter(paramSpec);
                }
            }

            JoinProcessor.ProcessDynamicFilterParameters(
                whereFragment,
                fragment,
                hqlSqlWalker
                );

            log.Debug("Using processed WHERE-fragment [" + fragment.Text + "]");

            // Filter conditions need to be inserted before the HQL where condition and the
            // theta join node.  This is because org.hibernate.loader.Loader binds the filter parameters first,
            // then it binds all the HQL query parameters, see org.hibernate.loader.Loader.processFilterParameters().
            if (fragment.FromElement.IsFilter || fragment.HasFilterCondition)
            {
                if (_filters == null)
                {
                    // Find or create the WHERE clause
                    IASTNode where = (IASTNode)query.WhereClause;
                    // Create a new FILTERS node as a parent of all filters
                    _filters = Create(HqlSqlWalker.FILTERS, "{filter conditions}");
                    // Put the FILTERS node before the HQL condition and theta joins
                    where.InsertChild(0, _filters);
                }

                // add the current fragment to the FILTERS node
                _filters.AddChild(fragment);
            }
            else
            {
                if (_thetaJoins == null)
                {
                    // Find or create the WHERE clause
                    IASTNode where = (IASTNode)query.WhereClause;

                    // Create a new THETA_JOINS node as a parent of all filters
                    _thetaJoins = Create(HqlSqlWalker.THETA_JOINS, "{theta joins}");

                    // Put the THETA_JOINS node before the HQL condition, after the filters.
                    if (_filters == null)
                    {
                        where.InsertChild(0, _thetaJoins);
                    }
                    else
                    {
                        _filters.AddSibling(_thetaJoins);
                    }
                }

                // add the current fragment to the THETA_JOINS node
                _thetaJoins.AddChild(fragment);
            }
        }
示例#9
0
        private static void ExtractColumnOrAliasNames(SqlString select, out List <SqlString> columnsOrAliases,
                                                      out Dictionary <SqlString, SqlString> aliasToColumn)
        {
            columnsOrAliases = new List <SqlString>();
            aliasToColumn    = new Dictionary <SqlString, SqlString>();

            IList <SqlString> tokens = new QuotedAndParenthesisStringTokenizer(select).GetTokens();
            int index = 0;

            while (index < tokens.Count)
            {
                SqlString token = tokens[index];

                int nextTokenIndex = index += 1;

                if (token.StartsWithCaseInsensitive("select"))
                {
                    continue;
                }

                if (token.StartsWithCaseInsensitive("distinct"))
                {
                    continue;
                }

                if (token.StartsWithCaseInsensitive(","))
                {
                    continue;
                }

                if (token.StartsWithCaseInsensitive("from"))
                {
                    break;
                }

                // handle composite expressions like "2 * 4 as foo"
                while ((nextTokenIndex < tokens.Count) && (tokens[nextTokenIndex].StartsWithCaseInsensitive("as") == false && tokens[nextTokenIndex].StartsWithCaseInsensitive(",") == false))
                {
                    SqlString nextToken = tokens[nextTokenIndex];
                    token          = token.Append(nextToken);
                    nextTokenIndex = index += 1;
                }

                // if there is no alias, the token and the alias will be the same
                SqlString alias = token;

                bool isFunctionCallOrQuotedString = token.IndexOfCaseInsensitive("'") >= 0 || token.IndexOfCaseInsensitive("(") >= 0;

                // this is heuristic guess, if the expression contains ' or (, it is probably
                // not appropriate to just slice parts off of it
                if (isFunctionCallOrQuotedString == false)
                {
                    // its a simple column reference, so lets set the alias to the
                    // column name minus the table qualifier if it exists
                    int dot = token.IndexOfCaseInsensitive(".");
                    if (dot != -1)
                    {
                        alias = token.Substring(dot + 1);
                    }
                }

                // notice! we are checking here the existence of "as" "alias", two
                // tokens from the current one
                if (nextTokenIndex + 1 < tokens.Count)
                {
                    SqlString nextToken = tokens[nextTokenIndex];
                    if (nextToken.IndexOfCaseInsensitive("as") >= 0)
                    {
                        SqlString tokenAfterNext = tokens[nextTokenIndex + 1];
                        alias  = tokenAfterNext;
                        index += 2;                         //skip the "as" and the alias
                    }
                }

                columnsOrAliases.Add(alias);
                aliasToColumn[alias] = token;
            }
        }
示例#10
0
 private static bool IsSelectStatement(SqlString sqlString)
 {
     return(sqlString.StartsWithCaseInsensitive("select"));
 }
示例#11
0
 private bool IsSelectQuery(SqlString sql)
 {
     return(sql.StartsWithCaseInsensitive("select"));
 }
示例#12
0
        protected SqlString GenerateIdInsertSelect(IQueryable persister, string tableAlias, IASTNode whereClause)
        {
            var            select         = new SqlSelectBuilder(Factory);
            SelectFragment selectFragment = new SelectFragment(Factory.Dialect)
                                            .AddColumns(tableAlias, persister.IdentifierColumnNames, persister.IdentifierColumnNames);

            select.SetSelectClause(selectFragment.ToFragmentString().Substring(2));

            string    rootTableName     = persister.TableName;
            SqlString fromJoinFragment  = persister.FromJoinFragment(tableAlias, true, false);
            SqlString whereJoinFragment = persister.WhereJoinFragment(tableAlias, true, false);

            select.SetFromClause(rootTableName + ' ' + tableAlias + fromJoinFragment);

            if (whereJoinFragment == null)
            {
                whereJoinFragment = SqlString.Empty;
            }
            else
            {
                whereJoinFragment = whereJoinFragment.Trim();
                if (whereJoinFragment.StartsWithCaseInsensitive("and "))
                {
                    whereJoinFragment = whereJoinFragment.Substring(4);
                }
            }

            SqlString userWhereClause = SqlString.Empty;

            if (whereClause.ChildCount != 0)
            {
                // If a where clause was specified in the update/delete query, use it to limit the
                // returned ids here...
                try
                {
                    var nodes = new CommonTreeNodeStream(whereClause);
                    var gen   = new SqlGenerator(Factory, nodes);
                    gen.whereClause();
                    userWhereClause = gen.GetSQL().Substring(7);
                }
                catch (RecognitionException e)
                {
                    throw new HibernateException("Unable to generate id select for DML operation", e);
                }
                if (whereJoinFragment.Length > 0)
                {
                    whereJoinFragment.Append(" and ");
                }
            }

            select.SetWhereClause(whereJoinFragment + userWhereClause);

            var insert = new InsertSelect();

            if (Factory.Settings.IsCommentsEnabled)
            {
                insert.SetComment("insert-select for " + persister.EntityName + " ids");
            }
            insert.SetTableName(persister.TemporaryIdTableName);
            insert.SetSelect(select);
            return(insert.ToSqlString());
        }