With many HQL queries, time and time again I am getting this exception:
Antlr.Runtime.NoViableAltException
This is really generic and unhelpful - does anyone know how best to debug this? Obviously it's a problem with my HQL - but without any clue as to what exactly is wrong it's very much a case of trial and error. I'm pulling my hair out every time I see this.
Note, I don't want to post any HQL here, becuase it's something that I am often coming across, not a problem related to one query.
Does anyone know the best way to tackle this? Is there any tool for validating HQL queries?
Have a look at NHibernate Query Analyzer. It is not perfect, but it will be helpful in many situations.
I can't help you directly, here's something I can share.
When dealing with hibernate or nhibernate (NH), I generally debug by enabling logging on the nhibernate's log4net, or/and the logging of queries at the DB side (e.g. mysql).
They can tell me what is the queries being formulated and executed at the DB and what are the exceptions thrown back by the DB.
For instance, if you have the following error:
Exception of type 'Antlr.Runtime.NoViableAltException' was thrown. near line 1, column
745 [select afe.AFEDataId, afe.Name, afe.AdditionalDescription, afe.ProjectType,
afe.BusinessUnit, afe.plantId, afe.fuelTypeId, afe.DisplayStatus, afe.BudgetedAmount,
sum(exp.Amount), afe.CreatedDate from Company.AFE.Model.AFEData as afe inner join
afe.Expenditures as exp inner join exp.ExpenditureType where (afe.Status.StatusId =
:statusId) and (afe.IsRestrictedVisibility = false OR (select count(AFEDataId) from
Company.AFE.Model.Reader as r where r.AFEData.AFEDataId = afe.AFEDataId AND
r.Contact.ContactId = '70bc6350-c466-40d5-a067-9d1f00bed7dc') > 0 OR (select count(AFEDataId)
from Company.AFE.Model.Editor as e where e.AFEData.AFEDataId = afe.AFEDataId AND
e.Contact.ContactId = '70bc6350-c466-40d5-a067-9d1f00bed7dc') > 0 OR 1=1) afe.AFEDataId,
afe.Name, afe.AdditionalDescription, afe.ProjectType, afe.BusinessUnit, afe.plantId,
afe.fuelTypeId, afe.DisplayStatus, afe.BudgetedAmount, afe.CreatedDate order by afe.Name ASC]
Go and look at character 745 from the original query that was provided and check to see if there is a spelling error, as there was in this one that I just looked at.
Which version of NH you used, for the latest version, the query exchange has some updated, such as you can't use "count(1)" in query, must change to count([alias name]), NH will translate to "select class.id from ... "
Related
I use Django 1.8.17 (I know it's not so young anymore).
I have logged slow requests on PostGres for more than one minute.
I have a lot of trouble finding the Queryset to which the SQL query listed in the logs belongs.
Is there an identifier that could be added to the Queryset to find the associated SQL query in the Logs or a trick to easily identify it?
Here is an exemple of common Queryset almost impossible to identify as I have several similars ones.
Queryset:
Video.objects.filter(status='online').order_by('created')
LOGs:
duration: 1056.540 ms statement: SELECT "video"."id", "video"."title",
"video"."description", "video"."duration", "video"."html_description",
"video"."niche_id", "video"."owner_id", "video"."views",
"video"."rating" FROM "video" WHERE "video"."status" = 'online'
ORDER BY "video"."created"
Desired LOGs:
duration: 1056.540 ms statement: SELECT "video"."id", "video"."title",
"video"."description", "video"."duration", "video"."html_description",
"video"."niche_id", "video"."owner_id", "video"."views",
"video"."rating" FROM "video" WHERE "video"."status" = 'online'
ORDER BY "video"."created" (ID=555)
Add middleware to log a warning when a query takes a long time:
class LongQueryLogMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
for q in connection.queries:
if float(q['time']) >= settings.LONG_QUERY_TIME_SEC:
logger.warning("Found long query (%s sec): %s", q['time'], q['sql'])
return response
I've made a small gist with all the code. Sorry for the indentation, GitHub keeps removing the indentation.
In the code above I only log the query, but you can add request information that will help you identify where the query comes from.
I don't know Django, so I may be off the mark, but there's a simple trick I heard from one of the people that runs RDS:
Add an identifier to your query as a comment.
So, include a UUID, ID, label, etc. to the query
-- as a comment
and that will flow through to the log. This is an easy way to tie Postgres log entries to specific methods/scripts, it sounds like it would need a bit of adaptation to be useful in your case. (If the idea applies at all.)
I have a list of Products with a field called 'Title' and I have been trying to get a list of initial letters with not much luck. The closes I have is the following that dosn't work as 'Distinct' fails to work.
atoz = Product.objects.all().only('title').extra(select={'letter': "UPPER(SUBSTR(title,1,1))"}).distinct('letter')
I must be going wrong somewhere,
I hope someone can help.
You can get it in python after the queryset got in, which is trivial:
products = Project.objects.values_list('title', flat=True).distinct()
atoz = set([i[0] for i in products])
If you are using mysql, I found another answer useful, albeit using sql(django execute sql directly):
SELECT DISTINCT LEFT(title, 1) FROM product;
The best answer I could come up with, which isn't 100% ideal as it requires post processing is this.
atoz = sorted(set(Product.objects.all().extra(select={'letter': "UPPER(SUBSTR(title,1,1))"}).values_list('letter', flat=True)))
I have been messing around with orientdb sql, and I was wondering if there is a way to update an edge of a vertex, together with some data on it.
assuming I have the following data:
Vertex: Person, Room
Edge: Inside (from Person to Room)
something like:
UPDATE Persons SET phone=000000, out_Inside=(
select #rid from Rooms where room_id=5) where person_id=8
obviously, the above does not work. It throws exception:
Error: java.lang.ClassCastException: com.orientechnologies.orient.core.id.ORecordId cannot be cast to com.orientechnologies.orient.core.db.record.ridbag.ORidBag
I tried to look at the sources at github searching for a syntax for bag with 1 item,
but couldn't find any (found %, but that seems to be for serialization no for SQL).
(1) Is there any way to do that then? how do I update a connection? Is there even a way, or am I forced to create a new edge, and delete the old one?
(2) When writing this, it came to my mind that perhaps edges are not the way to go in this case. Perhaps I should use a LINK instead. I have to say i'm not sure when to use which, or what are the implications involved in using any of them. I did found this though:
https://groups.google.com/forum/#!topic/orient-database/xXlNNXHI1UE
comment 3 from the top, of Lvc#, where he says:
"The suggested way is to always create an edge for relationships"
Also, even if I should use a link, please respond to (1). I would be happy to know the answer anyway.
p.s.
In my scenario, a person can only be at one room. This will most likely not change in the future. Obviously, the edge has the advantage that in case I might want to change it (however improbable that may be), it will be very easy.
Solution (partial)
(1) The solution was simply to remove the field selection. Thanks for Lvca for pointing it out!
(2) --Still not sure--
CREATE EDGE and DELETE EDGE commands have this goal: avoid the user to fight with underlying structure.
However if you want to do it (a little "dirty"), try this one:
UPDATE Persons SET phone=000000, out_Inside=(
select from Rooms where room_id=5) where person_id=8
update EDGE Custom_Family_Of_Custom
set survey_status = '%s',
apply_source = '%s'
where #rid in (
select level1_e.#rid from (
MATCH {class: Custom, as: custom, where: (custom_uuid = '%s')}.bothE('Custom_Family_Of_Custom') {as: level1_e} .bothV('Custom') {as: level1_v, where: (custom_uuid = '%s')} return level1_e
)
)
it works well
tl;dr
How to convert below SQL to Arel(or whatever is considered standard in Rails)
#toplist = ActiveRecord::Base.connection.execute(
'select ci.crash_info_id,
count(distinct(user_guid))[Occurences],
c.md5
from crashes ci
join crash_infos c on c.id=crash_info_id
group by ci.crash_info_id
order by [Occurences] desc')
--- end of tl;dr ----
I'm working on a small web project, it's goal is to take our customers crash reports(when our desktop app crashes, we send diagnostics to our servers), analyze them and then display what is the most common bug that causes our application to crash.. So that we concentrate on fixing bugs that affect biggest chunk of our users..
I have 2 tables:
crash_infos - id, md5(md5 of a stacktrace. in .net stacktrace and exception messages are sometimes translated by .net to user's native language! so I basically sanitize exception, by removing language specific parts and produce md5 out of it)
crashes - id, user_guid(user id), crash_info_id(id to crash_infos table)
Now the question, I wanted to make a query that shows most common crashes for unique user(avoid counting many times same crash for same user) and sort it by number of crashes. Unfortunately I didn't know enough Arel(or whatever is the ruby on rails way), so I ended up with raw SQL :(
#toplist = ActiveRecord::Base.connection.execute(
'select ci.crash_info_id,
count(distinct(user_guid))[Occurences],
c.md5
from crashes ci
join crash_infos c on c.id=crash_info_id
group by ci.crash_info_id
order by [Occurences] desc')
How can I convert this, to something more "railsy" ?
Thank you in advance
Not sure if this is actually any better but at least you should have a database independent query...
crashes = Arel::Table.new(:crashes)
crash_infos = Arel::Table.new(:crash_infos)
crashes.
project(crashes[:crash_info_id], crash_infos[:md5], Arel::Nodes::Count.new([crashes[:user_guid]], true, "occurences")).
join(crash_infos).on(crashes[:crash_info_id].eq(crash_infos[:id])).
group(crashes[:crash_info_id]).
order("occurences DESC").
to_sql
Gives:
SELECT "crashes"."crash_info_id", "crash_infos"."md5", COUNT(DISTINCT "crashes"."user_guid") AS occurences FROM "crashes" INNER JOIN "crash_infos" ON "crashes"."crash_info_id" = "crash_infos"."id" GROUP BY "crashes"."crash_info_id" ORDER BY occurences DESC
Is there anyway to use NHibernate in such a way that it whould only execute the query/queries once the returned object of a query/statement is used.. just like EF doest it?
For most instances with EF it wont send and execute the actual query to the database until the returned object of a linq-"statement" is used.. for instance:
var x = for e in entities.MyTable
select e;
This aint executed yet!
Which meens that Im able to mofidy the x-objects "linq-query" however I like without actualt "pulling" any data from the database:
x = x.Where(i=>i.SomeThing = someThing);
Still aint executed!
x.ToList<MyTable>()
Now its executed!
But in NHibernate the query gets executed once the transaction gets closed or commited from what I have understod.. and in most cases thats done already in the repository. So you can't simply in any other place alter the query and then send it to the database. Cause the query is already sent and that whould mean that you later on only whould alter whats "displayed" from the result.
I might have gotten this al wrong so please correct me if I am wrong.
Huge thanks in advance!
You can try something like this using detached QueryOver
var query = QueryOver.Of<Customer>()
.Where(x => x.LastName == "Smith"); // query is not executed yet
query.GetExecutableQueryOver(session).List();
Good thing is that you can pass QueryOver objects and get it executed somewhere else.