I need to know is it correct to use getAllRowsInRange() instead of RowSetIterator .
as we know , we need to close the result set to avoid memory leak.
the Question is : Do the getAllRowsInRange method cause a memory leak ? and how to handle that ?
--using getAllRowsInRange returninig array of Rows
ViewObject vo =app.findViewObject("VoName");
Row rows[] = vo.getAllRowsInRange();
for(Row r : Rows){
System.out.println("Attribute - " +r.getAttribute("AttributeName"));
}
--using createRowSetIterator returns a RowSetIterator we can close it
RowSetIterator rs = vo.createRowSetIterator(null);
rs.reset();
while(rs.hasNext()){
Row r = rs.next();
System.out.println("r - " + r);
System.out.println("Attribute - " +r.getAttribute("AttributeName"));
}
rs.closeRowSetIterator();
Related
I have the following SQL statement which I am trying to execute via JDBC PreparedStatement:
SELECT TOP(1) * FROM offsets sto WHERE sto.done = 0 AND sto.instance_index = 1
In my database this happily returns 1 row as it should.
But once I execute it in a JdbcTemplate:
private final String selectSql = "SELECT TOP(1) * " +
"FROM offsets sto " +
"WHERE sto.done = 0 " +
"AND sto.instance_index = ? ";
template.query(selectSql, new Object[]{1}, new int[]{Types.INTEGER} ,rs -> {
Offset offset = new Offset();
offset.setId(rs.getLong("id"));
offset.setInstance_index(rs.getInt("instance_index"));
offset.setDone(rs.getBoolean("done"));
return Optional.of(offset);
});
I get :
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The result set has no current row.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:237) ~[mssql-jdbc-9.4.0.jre11.jar:na]
at com.microsoft.sqlserver.jdbc.SQLServerResultSet.verifyResultSetHasCurrentRow(SQLServerResultSet.java:563) ~[mssql-jdbc-9.4.0.jre11.jar:na]
at com.microsoft.sqlserver.jdbc.SQLServerResultSet.getterGetColumn(SQLServerResultSet.java:2046) ~[mssql-jdbc-9.4.0.jre11.jar:na]
What is going on? What am I doing wrong?
The resultset starts before the first returned row. Call
rs.next();
Offset offset = new Offset();
offset.setId(rs.getLong("id"));
. . .
boolean next()
throws SQLException
Moves the cursor froward one row from its current position. A ResultSet cursor is initially positioned
before the first row; the first call to the method next makes the
first row the current row; the second call makes the second row the
current row, and so on. When a call to the next method returns false,
the cursor is positioned after the last row.
Resultset
I'm working through a stored procedure and wondering if there's a way to retrieve the anticipated result column list from a sql statement before fully executing.
Scenarios:
dynamic SQL
a UDF that might vary the columns outside of our control
EX:
//inbound parameter
SET QUERY_DEFINITION_ID = 12345;
//Initial statement pulls query text from bank of queries
var sqlText = getQueryFromQueryBank(QUERY_DEFINITION_ID);
//now we run our query
var cmd = {sqlText: sqlText };
stmt = snowflake.createStatement(cmd);
What I'd like to be able to do is say "right - before you run this, give me the anticipated column list" so I can compare it to what's expected.
EX:
Expected: [col1, col2, col3, col4]
Got: [col1]
Result: Oops. Don't run.
Rationale here is that I want to short-circuit the execution if something is missing - before it potentially runs for a while. I can validate all of this after the fact, but it would be really helpful to stop early.
Any ideas very much appreciated!
This sample SP code shows how to get a list of columns that a query will project into the result before you run the query. It should only be used for large, long running queries because it will take a few seconds to get the column list.
There are a couple of caveats. 1) It will only return the names of the columns. It won't tell you how they were built, that is, whether they're aliased, direct from a table, calculated, etc. 2) The example query I used is straight from the Snowflake documentation here https://docs.snowflake.com/en/user-guide/sample-data-tpcds.html#functional-query-definition. For convenience, I minimized the query to a single line. The output of the columns includes object qualifiers in addition to the column names, so V1.I_CATEGORY, V1.D_YEAR, V1.D_MOY, etc. If you don't want them to make it easier to compare names, you can strip off the qualifiers using the JavaScript split function on the dot and take index 1 of the resulting array.
create or replace procedure EXPLAIN_BEFORE_RUNNING()
returns string
language javascript
execute as caller
as
$$
// Set the context for the session to the TPC-H sample data:
executeNonQuery("use schema snowflake_sample_data.tpcds_sf10tcl;");
// Here's a complex query from the Snowflake docs (minimized to one line for convienience):
var sql = `with v1 as( select i_category, i_brand, cc_name, d_year, d_moy, sum(cs_sales_price) sum_sales, avg(sum(cs_sales_price)) over(partition by i_category, i_brand, cc_name, d_year) avg_monthly_sales, rank() over (partition by i_category, i_brand, cc_name order by d_year, d_moy) rn from item, catalog_sales, date_dim, call_center where cs_item_sk = i_item_sk and cs_sold_date_sk = d_date_sk and cc_call_center_sk= cs_call_center_sk and ( d_year = 1999 or ( d_year = 1999-1 and d_moy =12) or ( d_year = 1999+1 and d_moy =1)) group by i_category, i_brand, cc_name , d_year, d_moy), v2 as( select v1.i_category ,v1.d_year, v1.d_moy ,v1.avg_monthly_sales ,v1.sum_sales, v1_lag.sum_sales psum, v1_lead.sum_sales nsum from v1, v1 v1_lag, v1 v1_lead where v1.i_category = v1_lag.i_category and v1.i_category = v1_lead.i_category and v1.i_brand = v1_lag.i_brand and v1.i_brand = v1_lead.i_brand and v1.cc_name = v1_lag.cc_name and v1.cc_name = v1_lead.cc_name and v1.rn = v1_lag.rn + 1 and v1.rn = v1_lead.rn - 1) select * from v2 where d_year = 1999 and avg_monthly_sales > 0 and case when avg_monthly_sales > 0 then abs(sum_sales - avg_monthly_sales) / avg_monthly_sales else null end > 0.1 order by sum_sales - avg_monthly_sales, 3 limit 100;`;
// Before actually running the query, generate an explain plan.
executeNonQuery("explain " + sql);
// Now read the column list from the explain plan from the result set.
var columnList = executeSingleValueQuery("COLUMN_LIST", `select "expressions" as COLUMN_LIST from table(result_scan(last_query_id())) where "operation" = 'Result';`);
// For now, just exit with the column list as the output...
return columnList;
// Your code here...
// Helper functions:
function executeNonQuery(queryString) {
var out = '';
cmd = {sqlText: queryString};
stmt = snowflake.createStatement(cmd);
var rs;
rs = stmt.execute();
}
function executeSingleValueQuery(columnName, queryString) {
var out;
cmd1 = {sqlText: queryString};
stmt = snowflake.createStatement(cmd1);
var rs;
try{
rs = stmt.execute();
rs.next();
return rs.getColumnValue(columnName);
}
catch(err) {
if (err.message.substring(0, 18) == "ResultSet is empty"){
throw "ERROR: No rows returned in query.";
} else {
throw "ERROR: " + err.message.replace(/\n/g, " ");
}
}
return out;
}
$$;
call Explain_Before_Running();
I am getting an error on applying a raw query in sq-lite.The error is
Caused by: android.database.sqlite.SQLiteException: near "Limit": syntax error (code 1): ,
while compiling: SELECT * FROM quiz_questions WHERE Levels = "Level 1"+ Limit 2+
The query SELECT * FROM quiz_questions WHERE Levels = "Level 1" works and gives me multiple rows but when i am applying limit to query, it gives error.
This is code for it.
public ArrayList<Question> getLockedLevels(ArrayList<String> Level) {
ArrayList<Question> questionList = new ArrayList<>();
db = getReadableDatabase();
for (int i = 0; i < Level.size(); i++)
{
String levelID = Level.get(i);
String SELECT_TABLE_QUERY = "SELECT * FROM " + TABLE_NAME + " WHERE " + COLUMN_LEVEL + " = \"" + levelID + "\"+ Limit 1";
Cursor cursor = db.rawQuery(SELECT_TABLE_QUERY, null);
if (cursor.moveToFirst()) {
do {
Question question = new Question();
question.setmLevels(cursor.getString(cursor.getColumnIndex(COLUMN_LEVEL)));
question.setmLevels_lockmanager(cursor.getInt(cursor.getColumnIndex(COLUMN_LEVEL_LOCKMANAGER)));
questionList.add(question);
} while (cursor.moveToNext());
}
cursor.close();
}
return questionList;
}
Try
String SELECT_TABLE_QUERY = "SELECT * FROM " + TABLE_NAME + " WHERE " + COLUMN_LEVEL + " = '" + levelID + "' Limit 1";
That should resovle to :-
SELECT * FROM quiz_questions WHERE Levels = 'Level 1' Limit 1
However, the above is subject to potential SQL Injection.
Using :-
String levelID = Level.get(i);
String SELECT_TABLE_QUERY = "SELECT * FROM " + TABLE_NAME + " WHERE " + COLUMN_LEVEL + "=? Limit 1";
Cursor cursor = db.rawQuery(SELECT_TABLE_QUERY, new String[]{levelID });
would remove the potential for SQL Injection and is therefore considered the more correct way.
Alternatively you could utilise the convenience query method that not only protects against SQL Injection but also generates much of the SQL.
So you could use :-
for (int i = 0; i < Level.size(); i++) {
Cursor cursor = db.query(TABLE_NAME,null,COLUMN_LEVEL + "=?",new String[]{Level.get(i)},null,null,null,"1");
while (cursor.moveToNext()) {
Question question = new Question();
question.setmLevels(cursor.getString(cursor.getColumnIndex(COLUMN_LEVEL)));
question.setmLevels_lockmanager(cursor.getInt(cursor.getColumnIndex(COLUMN_LEVEL_LOCKMANAGER)));
questionList.add(question);
}
cursor.close();
}
See SQliteDatabase - query
The above also uses the shorter while(cursor.moveToNext) { ..... } for looping through the Cursor (if there are no rows then the loop is not entered as moveToNext will return false if the move cannot be made)
In SQL we can use the "WHERE 1=1 hack" to easily generate a WHERE statement in a loop, so we don't need to check if the current iteration is the first one.
without WHERE 1 :
//I haven't tried the C++ code below, it's just an example to briefly explain the "hack"
string statement = "WHERE";
for (int i = 0 ; i < list.size() ; i++)
{
if (i != 0)
{
statement += " AND "; //we don't want to generate "WHERE AND"
}
statement += list[i];
}
the generated statement :
WHERE <something_1>
AND <something_2>
AND <something_3>
with WHERE 1 :
string statement = "WHERE 1 = 1"; // Added "1 = 1"
for (int i = 0 ; i < list.size() ; i++)
{
statement += "AND" + list[i];
}
the generated statement :
WHERE 1 = 1
AND <something_1>
AND <something_2>
AND <something_3>
My issue : I need to generate an "ORDER BY" statement, and I was wondering if such a hack also exists for the ORDER BY statement.
I could check if the current iteration in the loop is the last one, but there's maybe a better solution.
ORDER BY a DESC,
b DESC,
c DESC,
d DESC,
<dummy statement added at the end, so I don't need to remove the last comma>
From what I've read I cannot use "ORDER BY 1", so does a similar hack actually exists?
You could legally start every ORDER BY with something like:
order by ##spid
But it's likely to raise questions about query execution efficiency.
What you said about not using "1" is only partially true. If you did a similar pattern, adding "1" at the end would work as long as whatever column is in position 1 isn't also referenced in the order by clause.
I generally do something like this:
string whereClause = (list.Count > 0)
? "WHERE (" + list.StringJoin(") AND (") + ")"
: "";
where StringJoin is a very simple extension method I wrote. Note the added parentheses so that if any of the list elements have an "OR" you don't get into trouble.
Something identical can be done for ORDER BY, just replacing the word WHERE above.
string orderClause = (list.Count > 0)
? "ORDER BY " + list.StringJoin(", ")
: "";
This is C# instead of c++, but a simple version of the extension method is this:
public static string StringJoin(this IEnumerable<string> list, string separator)
{
if (list == null)
return null;
else
return string.Join(separator, list.ToArray());
}
I'm trying to create an array based on a pivot table with multiple empty cells, however instead of referring to previous value, the array keeps all the empty cells:
For AllCostTypeRowCounter = 1 To SiteRowCount
AllCostTypeArrayCounter = AllCostTypeArrayCounter + 1
ReDim Preserve AllCostTypeArray(2, AllCostTypeArrayCounter)
If Not CountryRange(AllCostTypeRowCounter, 1) Is Nothing Then
AllCostTypeArray(1, AllCostTypeArrayCounter) = CountryRange(AllCostTypeRowCounter, 1)
Else
AllCostTypeArray(1, AllCostTypeArrayCounter) = AllCostTypeArray(1, AllCostTypeArrayCounter - 1)
End If
AllCostTypeArray(2, AllCostTypeArrayCounter) = SiteRange(AllCostTypeRowCounter, 1).Value
Next AllCostTypeRowCounter
Nvm I solved the question by changing the following code:
If Not CountryRange(AllCostTypeRowCounter, 1) Is Nothing Then
to:
If CountryRange(AllCostTypeRowCounter, 1) <> "" Then
Can anyone tell me why this change works. The above seems the same to me. Also how do I close my own post?