xBestIndex malfunction (passing non-literal parameters to table valued function) - sqlite

I'm trying to implement a table valued function (as a SQLite virtual table).
It's a function that would take a string and return a table with all the words of the string.
If I call it with literal values like below, it works fine.
SELECT word FROM splitstring("abc def ghi")
If, however, I call it with a column from another table it doesn't work:
SELECT a.Name, word FROM article a, splitstring(a.Text)
The xBestIndex method gets called all right, but right after that, I get an exception from the ExecuteReader method. The exception message is "xBestIndex malfunction". The xFilter method does not get called because of the exception.
My xBestIndex implementation is simple, it just marks the parameter so I can see it in xFilter:
public override SQLiteErrorCode BestIndex(SQLiteVirtualTable table, SQLiteIndex index)
{
index.Outputs.ConstraintUsages.ElementAt(0).argvIndex = 1;
index.Outputs.ConstraintUsages.ElementAt(0).omit = 1;
return SQLiteErrorCode.Ok;
}
Am I'm doing something wrong or is it impossible to pass non-literal parameters to table valued functions?

Found the issue! I was using constraints that had usable=0. The BestIndex method gets called multiple times by SQLite, the second time with a non-usable constraint.
Here is the fixed body of the BestIndex method.
public override SQLiteErrorCode BestIndex(SQLiteVirtualTable table, SQLiteIndex index)
{
if (index.Inputs.Constraints.Count() != 2)
throw new ArgumentException("The generate_series function requires two integer (long) parameters!");
if (index.Inputs.Constraints.All(c=>c.usable == 1))
{
index.Outputs.ConstraintUsages.ElementAt(0).argvIndex = 1;
index.Outputs.ConstraintUsages.ElementAt(0).omit = 1;
index.Outputs.ConstraintUsages.ElementAt(1).argvIndex = 2;
index.Outputs.ConstraintUsages.ElementAt(1).omit = 1;
}
else
{
index.Outputs.IndexNumber = -1;
index.Outputs.EstimatedCost = double.MaxValue;
}
return SQLiteErrorCode.Ok;
}
Now I check the usable flag. When BestIndex gets called with a constraint with usable=0 I skip it i.e. return a high estimated cost for that index so it doesn't get used.

Related

Number of records in grid AX 2012

I tried to count num of rows in grid in runtime with this code
FormRun caller;
FormDataSource fds;
QueryRun queryRun;
int64 rows;
fds = caller.dataSource();
query = fds.query();
queryRun = new QueryRun(query);
rows = SysQuery::countTotal(queryRun); //this returns -1587322268
rows = SysQuery::countLoops(queryRun); //this returs 54057
The last line of code is closest to what i need because there are 54057 lines but if i add filters it still returns 54057.
I want logic to get the number rows that grid has in the moment of calling the method.
Your query has more than one datasource.
The best way to explain your observation is to look at the implementation of countTotal and countLoops.
public client server static Integer countTotal(QueryRun _queryRun)
{
container c = SysQuery::countPrim(_queryRun.pack(false));
return conpeek(c,1);
}
public client server static Integer countLoops(QueryRun _queryRun)
{
container c = SysQuery::countPrim(_queryRun.pack(false));
return conpeek(c,2);
}
private server static container countPrim(container _queryPack)
{
...
if (countQuery.dataSourceCount() == 1)
qbds.addSelectionField(fieldnum(Common,RecId),SelectionField::Count);
countQueryRun = new QueryRun(countQuery);
while (countQueryRun.next())
{
common = countQueryRun.get(countQuery.dataSourceNo(1).table());
counter += common.RecId;
loops++;
}
return [counter,loops];
}
If your datasource contains one datasource it adds count(RecId).
countTotal returns the number of records.
countLoops returns 1.
Pretty fast, as fast as the SQL allows.
If your datasource contains more than one datasource it does not add count(RecId).
countTotal returns the sum of recIds (makes no sense).
countLoops returns the number of records.
Also countLoops is slow if there are many records as they are counted one by one.
If you have two datasources and want a fast count, you are on your own:
fds = caller.dataSource();
queryRun = new QueryRun(fds.queryRun().query());
queryRun.query().dataSourceNo(2).joinMode(JoinMode::ExistsJoin);
queryRun.query().dataSourceNo(1).clearFields();
queryRun.query().dataSourceNo(1).addSelectionField(fieldnum(Common,RecId),SelectionField::Count);
queryRun.next();
rows = queryRun.getNo(1).RecId;
The reason your count did not respect the filters was because you used datasource.query() rather than datasource.queryRun().query(). The former is the static query, the latter is the dynamic query with user filters included.
Update, found some old code with a more general approach:
static int tableCount(QueryRun _qr)
{
QueryRun qr;
Query q = new Query(_qr.query());
int dsN = _qr.query().dataSourceCount();
int ds;
for (ds = 2; ds <= dsN; ++ds)
{
if (q.dataSourceNo(ds).joinMode() == JoinMode::OuterJoin)
q.dataSourceNo(ds).enabled(false);
else if (q.dataSourceNo(ds).joinMode() == JoinMode::InnerJoin)
{
q.dataSourceNo(ds).joinMode(JoinMode::ExistsJoin);
q.dataSourceNo(ds).fields().clearFieldList();
}
}
q.dataSourceNo(1).fields().clearFieldList();
q.dataSourceNo(1).addSelectionField(fieldNum(Common,RecId), SelectionField::Count);
qr = new QueryRun(q);
qr.next();
return any2int(qr.getNo(1).RecId);
}

Upper and/lower queriable values jdeveloper

I have a query form in a jspx file and i'm trying to define some of the values as case sensitive, meaning that i want to be able to find, for example, a name with all letters upper case and/or lower case and obtain the values that i would obtain if i've inserted the name correctly.
Can someone indicate me where can i find something to accomplish that?
Thanks in advance
--------Update
Code from my jspx file
<af:query id="qryId1" headerText="Search" disclosed="true"
value="#bindings.ImplicitViewCriteriaQuery.queryDescriptor}"
model="#bindings.ImplicitViewCriteriaQuery.queryModel}"
queryListener="#bindings.ImplicitViewCriteriaQuery.processQuery}"
queryOperationListener="#{bindings.ImplicitViewCriteriaQuery.processQueryOperation}"
resultComponentId="::resId1"
binding="#{backingBeanScope.backing_SearchCustomer.qryId1}"
maxColumns="3" rows="2" fieldWidth="30%"
displayMode="compact" saveResultsLayout="never"
saveQueryMode="hidden" modeChangeVisible="false"/>
In a view criteria, for each criteria item there is a check box Ignore Case. Uncheck it if you want to make that search field case sensitive.
If you are using All Queriable Attributes to create your search then you can set it in queryListner method of the query component. Here are the steps:
Create a queryListener method for your query component
<af:query id="qryId1" headerText="Search" disclosed="true"
value="#{bindings.ImplicitViewCriteriaQuery.queryDescriptor}"
model="#{bindings.ImplicitViewCriteriaQuery.queryModel}"
queryListener="#{backingBeanScope.searchBean.queryListener}"
queryOperationListener="#{bindings.ImplicitViewCriteriaQuery.processQueryOperation}"
resultComponentId="::resId1"/>
Make query attributes case insensitive in queryListener method
public void queryListener(QueryEvent queryEvent)
{
QueryDescriptor qdesc = (QueryDescriptor) queryEvent.getDescriptor();
ConjunctionCriterion conCrit = qdesc.getConjunctionCriterion();
//access the list of search fields
List<Criterion> criterionList = conCrit.getCriterionList();
for (Criterion criterion: criterionList)
{
((AttributeCriterion) criterion).setMatchCase(false);
}
invokeMethodExpression( "#{bindings.ImplicitViewCriteriaQuery.processQuery}", queryEvent);
}
private void invokeMethodExpression(String expr, QueryEvent queryEvent)
{
FacesContext fctx = FacesContext.getCurrentInstance();
ELContext elContext = fctx.getELContext();
ExpressionFactory eFactory =
fctx.getApplication().getExpressionFactory();
MethodExpression mexpr =
eFactory.createMethodExpression(elContext, expr, Object.class,
new Class[]
{ QueryEvent.class });
mexpr.invoke(elContext, new Object[]
{ queryEvent });
}

Faster database access by index

I have this code
using (var contents = connection.CreateCommand())
{
contents.CommandText = "SELECT [subject],[note] FROM tasks";
var r = contents.ExecuteReader();
int zaehler = 0;
int zielzahl = 5;
while (r.Read())
{
if (zaehler == zielzahl)
{
//access r["subject"].ToString()
}
zaehler++;
}
}
I want to make it faster by accessing zielzahl directly like r[zielzahl] instead of iterating through all entries. But
r[zielzahl]["subject"]
does not work aswell as
r["subject"][zielzahl]
How do I access the column subject of result number zielzahl?
To get only the sixth record, use the OFFSET clause:
SELECT subject, note
FROM tasks
LIMIT 1 OFFSET 5
Please note that the order of returned records is not guaranteed unless you use the ORDER BY clause.

drupal_map_assoc($array)

function _ahah_example_get_first_dropdown_options() {
$stid = oci_parse($conn, "SELECt code,descr1 FROM dbtest.regions");
oci_execute($stid);
$region= array();
while (($row = oci_fetch_array($stid, OCI_ASSOC))) {
$region[$row['CODE']]= $row['DESCR1'];
}
$region['']='Select';
oci_free_statement($stid);
oci_close($conn);
return drupal_map_assoc($region);
}
but it returns the key and the value equal I need the original key to be returne cause im using it's value in a javascript function?anyone would know how to return the original Key?
From your code, you should be able to skip drupal_map_assoc and just return $region. Give that a try and see if you like the results.
Reference http://api.drupal.org/api/drupal/includes--common.inc/function/drupal_map_assoc/6

Error: FormatException was unhandled by user code in Linq how to solve?

Look please below this codes throw me : FormatException was unhandled by user code
Codes:
satis.KDV = Decimal.Parse((from o in genSatisctx.Urun where o.ID == UrunID select o.Kdv).ToString());
How can i rewrite linq query?
You are calling ToString on the query rather than a single result. Even though you may expect only one value to match your query, it will not return just a single value. You have to instruct it to do so using Single, First, Last or the variations of these that also return a default value (SingleOrDefault, FirstOrDefault, LastOrDefault).
In order to avoid an exception, you could change it to use Decimal.TryParse or you could change your code to use a default value if the LINQ query returns something that won't parse properly. I'd recommend the former or a combination.
Note that in the following example, I have added the call to SingleOrDefault. This ensures that only one value is parsed, even if no value is found, and that if there are multiple results, we get an exception (i.e. it enforces that we get exactly zero or one result to the query).
decimal parsedValue;
if (Decimal.TryParse(
genSatisctx
.Urun
.Where(o => o.ID == UrunID)
.Select(o=>o.Kdv)
.SingleOrDefault()
.ToString(), out parsedValue))
{
satis.KDV = parsedValue;
}
You're calling ToString() on an IQueryable<T> - what did you expect the string to be? It's very unlikely to be anything which can be parsed as a decimal number!
My guess is that you want to call First() or Single(), but we can't really tell without more information. What's the type of o.Kdv?
I suspect you either want:
satis.KDV = (from o in genSatisctx.Urun
where o.ID == UrunID
select o.Kdv).First();
or
string kdvString = (from o in genSatisctx.Urun
where o.ID == UrunID
select o.Kdv).First();
decimal kdv;
if (decimal.TryParse(kdvString, out kdv))
{
satis.KDV = kdv;
}
else
{
// What do you want to do if it's not valid?
}
When I use debug mode I see the data is update when over mouse, after end of this method ( it's show this message [input string was not in a correct format]
/* protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
try
{
TextBox name = (TextBox)GridView1.Rows[e.RowIndex].FindControl("txtEditName");
SqlDataSource2.UpdateParameters["Name"].DefaultValue = name.ToString();
TextBox age = (TextBox)GridView1.Rows[e.RowIndex].FindControl("txtEditAge");
SqlDataSource2.UpdateParameters["Age"].DefaultValue = age.ToString();
TextBox birthday = (TextBox)GridView1.Rows[e.RowIndex].FindControl("txtEditBirthday");
SqlDataSource2.UpdateParameters["Birthday"].DefaultValue = birthday.ToString();
DropDownList country = (DropDownList)GridView1.Rows[e.RowIndex].FindControl("DropEditCountry");
SqlDataSource2.UpdateParameters["CountryID"].DefaultValue = country.SelectedValue;
TextBox mobile = (TextBox)GridView1.Rows[e.RowIndex].FindControl("txtEditMobile");
SqlDataSource2.UpdateParameters["Mobile_No"].DefaultValue = mobile.ToString();
SqlDataSource2.Update();
}
catch (Exception j)
{
j.Message.ToString();
}
}
/* }

Resources