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); }
/// <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) }); } }
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); }
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); } }
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; } }
private static bool IsSelectStatement(SqlString sqlString) { return(sqlString.StartsWithCaseInsensitive("select")); }
private bool IsSelectQuery(SqlString sql) { return(sql.StartsWithCaseInsensitive("select")); }
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()); }