Pro*C Oracle -- looping through sql fetch - sql

I'm beginning with Pro*C and have a program that reads in records and prints out grouped by an identifying value (guests). In order to get all the information printed, I used a break from the for loop to control what goes where. It compiles but it's not following the printing scheme and actually goes into an infinite loop. The last break at the end is to stop the infinite loop, and it's not hitting any of the conditionals for some reason (even with a default else). There's limited debugging on the remote database server it's executing on (dbx is not available).
While not end of cursor (ie. sqlcode = 0)
If PrevSaleItem Not = Cursor.Item_ID
Write The Subtotals for the Item
Initialize ItemQty and ItemTotal to 0
Set PrevSaleItem to Cursor.Item_ID
End if
Print Out Detail Line
Add Cursor.Quantity to ItemQty
Add Cursor.calc_tax to ItemTotal and GuestTotal
Fetch next record in cursor
End While
Print the Subtotals for the last item
Print the Grand totals
exec sql open dbGuest;
exec sql fetch dbGuest into :sLastName, :sFirstName, :nItemID, :sItemName, :nQuantity, :nUnitPrice, :sTransDate, :sHotelName, :nHotelID, :sTaxable, :nCalcTax;
/* Lets check the status of the OPEN statement before proceeding , else exceptions would be suppressed */
if(sqlca.sqlcode !=0) // If anything went wrong or we read past eof, stop the loop
{
printf("Error while opening Cursor <%d><%s>\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
break;
}
int PrevSaleItem = 0;
int ItemQty = 0;
double ItemTotal = 0.0;
double GuestTotal = 0.0;
for(;;)
{
printf("%s %s %s %s %d\n","Charge Summary for:", sFirstName.arr, sLastName.arr, " Guest_ID:", nGuest_ID);
printf("%s %d %s %s \n", "Sales_Item: ", nItemID, " - ", sItemName.arr);
// Do the crazy stuff to end the C-Strings
sLastName.arr[sLastName.len] = 0;
sFirstName.arr[sFirstName.len] = 0;
sItemName.arr[sItemName.len] = 0;
sTransDate.arr[sTransDate.len] = 0;
sHotelName.arr[sHotelName.len] = 0;
sTaxable.arr[sTaxable.len] = 0;
// initialize
PrevSaleItem = nItemID;
ItemQty = 0;
ItemTotal = 0.0;
GuestTotal = 0.0;
//While not end of cursor (ie. sqlcode = 0)
/* Check for No DATA FOUND */
if (sqlca.sqlcode == 0)
{
if(PrevSaleItem != nItemID)
{
printf("ItemQty: %f \t ItemTotal: %f",ItemQty,ItemTotal);
ItemTotal = 0.0;
GuestTotal = 0.0;
PrevSaleItem = nItemID;
}
printf("GuestTotal \t\t %f",GuestTotal);
ItemQty += nQuantity;
ItemTotal += nCalcTax;
GuestTotal += nCalcTax;
}
else if(sqlca.sqlcode == 100 || sqlca.sqlcode == 1403) // If anything went wrong or we read past eof, stop the loop
{
printf("CURSOR is empty after all fetch");
PrevSaleItem = -1;
break;
}
/* Check for other errors */
else if(sqlca.sqlcode != 0)
{
printf("Error while fetching from Cursor <%d><%s>\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
break;
}
else {printf("HIT ELSE"); break;}
break;
}
// close the cursor and end the program
exec sql close dbGuest ;
The logic that should be happening is as follows:
Assume the break mechanism is within an outer for loop (not shown). It should open the cursor, fetch the 1st record, and then print the heading for the guest and the sales item. It then initializes the totals and break variables by setting the values. While not the end of cursor (sqlcode is 0, and instead of while just used for loop with break) if the previous item != the item id then it prints subtotals, initializes item quantities and totals to 0 and sets the previous item to item id (then breaks the if conditional). Item quantity is increased by the quantity in the table, and the calc_tax is added to the item and guest totals. The next record is fetched, the totals for that last item are printed, and then the grand totals for that guest are printed.
It's not printing the amounts where it should be and is in infinite loop, and after I tried breaks in all the conditionals, I'm at a loss to explain how it's happening. I'm sure it's a beginner mistake, so maybe a jr Oracle developer (but a pro would be great) has a moment to get me back on track here.

Your fetch is outside the for loop. You go into the loop after the first fetch. If sqlca.sqlcode is zero after that first fetch, it isn't reaching any of the breaks because of the nested if and else, so it goes round the loop again. Becuase there is not a second fetch, you still have a good sqlcode, so it keeps going. I think.... Anyway, moving your fetch into the loop looks like what you want to happen?
It does look like that final break should kick in, but yesterday you posted code you'd modified so I'm not sure if that's the case here too.
If you reformat your code and introduce braces and nesting for the else conditions you can see they don't line up. The final { you showed isn't for the for, it's for one of the branches.
for(;;)
{
if (sqlca.sqlcode == 0)
{
if(PrevSaleItem != nItemID)
{
...
}
....
}
else
{
if(sqlca.sqlcode == 100 || sqlca.sqlcode == 1403)
{
break;
}
else
{
if(sqlca.sqlcode != 0)
{
break;
}
else
{
printf("HIT ELSE");
break;
}
break;
}
// close the cursor and end the program
exec sql close dbGuest ;
The else if(sqlca.sqlcode != 0) is redundant; at this point sqlca.sqlcode has to be something other than 0, 100 or 1403. So it can't reach the next else either.

Related

Number of filled rows in a SapTable

I'm using Silk4J and I have a table which is reported as SapTable in the Locator Spy. From that table, I'm trying to get all the texts of the second column, but it hangs or terminates with an exception. In the following you find the code for my tries. Finally I reached the last row of the table, but it hangs there again.
In all examples I'm using a while loop instead of a for loop, because I want to insert more conditions later.
Try 1: Straight forward (I thought)
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
}
However, this code prints all visible columns, then hangs.
Try 2: adding a PageDn keypress via Silk
Since try 1 printed only the visible cells, I thought adding a keypress every page could help. That was my code:
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
int visibleRows = table.getVisibleRowCount();
table.setFocus();
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
if (row % visibleRows == 0)
window.sendVKey(VKey.PAGE_DOWN);
}
Unfortunately this results in an exception "The virtual key is not enabled".
Try 3: adding a PageDn keypress via AwtRobot
Since the built-in sendVKey method did not work, but pressing the PageDn manually works, I switched to an AwtRobot:
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
int visibleRows = table.getVisibleRowCount();
table.setFocus();
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
if (row % visibleRows == 0)
{
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_PAGE_DOWN);
robot.keyRelease(KeyEvent.VK_PAGE_DOWN);
}
}
Pressing the key now works and I can see the table scroll to the next entry. However, my test application still hangs.
Try 4: Resetting the row count
Using the Locator Spy again, I found out that the index of the row is reset to zero, so I mimiced that in my code:
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
int visibleRows = table.getVisibleRowCount();
table.setFocus();
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
if (row % visibleRows == 0)
{
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_PAGE_DOWN);
robot.keyRelease(KeyEvent.VK_PAGE_DOWN);
row = 0; // <--
}
}
In this case, it prints the first N (number of visible) items of the list, scrolls to position N+1, prints the name of the first (!) row and then hangs when accessing the item with index 1 (after the reset).
Try 5: Sleeping
With some sleeping, I can reach the end of the table:
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
int visibleRows = table.getVisibleRowCount();
table.setFocus();
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
if (row % visibleRows == 0)
{
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_PAGE_DOWN);
robot.keyRelease(KeyEvent.VK_PAGE_DOWN);
row = 0;
Thread.sleep(1000); // <--
}
}
In this case, I get all items in the table. But since I don't know when the table ends, it does another getCell() call, which results in a hang again.
The question
I'm really stuck. I've also looked for other methods like getting the real number of rows in the table (getRowCount() doesn't), but didn't find one yet.
How do I get the real number of rows of a SapTable in Silk4J?
It took some trying - the underlying SAP automation API is not really helpful in this case - but here is how you can make it work:
private List<String> fetchItems() {
SapTable table = desktop.find("sap.Table");
SapVerticalScrollBar scrollBar = table.find("/SapVerticalScrollBar");
// the scrollbar maximum value seems to be a more reliable
// way to get the number of items than getRowCount
int itemCount = scrollBar.getMaximum() + 1;
List<String> items = new ArrayList<String>();
int currentAbsoluteRow = 0;
// the first loop iterates through the table page by page
for (int firstRowInPage = 0;
firstRowInPage < itemCount;
firstRowInPage = scrollToNextPage(firstRowInPage)) {
// this loop goes through the items of the current page
for (int currentRowInPage = 0;
currentRowInPage < table.getVisibleRowCount();
currentRowInPage++) {
if(++currentAbsoluteRow > itemCount) {
// we've read all the available items
return items;
}
SapComponent cell = table.getCell(currentRowInPage, 1);
items.add(cell.getProperty("Text").toString());
}
}
return items;
}
private int scrollToNextPage(int firstRowInPage) {
SapTable table = desktop.find("sap.Table");
SapVerticalScrollBar scrollBar = table.find("/SapVerticalScrollBar");
firstRowInPage += scrollBar.getPageSize();
scrollBar.scrollTo(firstRowInPage);
return firstRowInPage;
}
Some pitfalls that I encountered:
getRowCount() returned a higher count than there was in actual items
getVisibleRowCount() returns the number of items that would fit on the current page, even if not all rows were filled with actual items
The returned cell objects are only valid as long as the cell is on the screen, so you'll need to pull the information you want before you scroll to the next page.

Use multiple return statement

Is there a considerable difference of optimization between these two codes (in Java and/or C++, currently, even if I guess it's the same in every languages) ? Or is it just a question of code readability ?
int foo(...) {
if (cond) {
if (otherCondA)
return 1;
if (otherCondB)
return 2;
return 3;
}
int temp = /* context and/or param-dependent */;
if (otherCondA)
return 4 * temp;
if (otherCondB)
return 4 / temp;
return 4 % temp;
}
and
int foo(...) {
int value = 0;
if (cond) {
if (otherCondA)
value = 1;
else if (otherCondB)
value = 2;
else value = 3;
}
else {
int temp = /* context and/or param-dependent */;
if (otherCondA)
value = 4 * temp;
else if (otherCondB)
value = 4 / temp;
else
value = 4 % temp;
}
return value;
}
The first one is shorter, avoid multiple imbrications of else statement and economize one variable (or at least seems to do so), but I'm not sure that it really changes something...
After looking deeper into the different assembly codes generated by GCC, here's the results :
The multiple return statement is more efficient during "normal" compilation, but with the -O_ flag, the balance change :
The more you optimise the code, the less the first approach worths. It makes the code harder to optimise, so, use it carefully. As said in comments, it's very powerful when used at the front of the function when testing preconditions, but in the middle of the function, it's a nightmare for the compiler.
Of course the multiple return is acceptable.
Because you can halt the program as soon as the function is finished

get the number of parents that equal to the sum of children

i have a problem with the below code. i need to get the number of parents that it's value = to the sum of it's 2 children. example if parent value = 10 and its children are 2 and 8.
then i have to count this parent as 1. i need to check for all nodes in the tree.
this is what i tried to do: could you please advise:
int BinaryTree::numberOfSum (){
return numberOfSumImpl (root);
}
int BinaryTree::numberOfSumImpl (BTNode *rootNode, int el){
if(rootNode ==0) return 0;
int count=0;
if(rootNode->hasTwoChildren() || rootNode->isLeaf())
else if{
if (rootNode->info==el) return count=1;
return count + numberOfSumImpl(el,rootNode->left) + numberOfSumImpl(el,rootNode->right);
}
}
Many Thanks,
There seem to be a few problems with the call to numberOfSumImpl, as in the main function it is only called with one parameter, and in the recursive function it is called with two parameters, but with the order inversed. This code does not even compile!
Besides, the condition rootNode->hasTwoChildren() || rootNode->isLeaf()) looks strange and, having its body empty even more strange.
You did not post the definition of the BTNode, but looks like you are looking for something as
int BinaryTree::numberOfSumImpl (BTNode* p) {
if (not p) return 0;
int count;
if (p->hasTwoChildren() and p->info == p->left->info + p->right->info) {
count = 1;
} else {
count = 0;
}
return count + numberOfSumImpl(p->left) + numberOfSumImpl(p->right);
}
And this function would possibly be static.

My program doesn't get into my second for loop

While doing some work for my lab in university
I am creating this function where there is a for loop inside another one.
It is not important to know what the method is used for. I just can't figure out why the program doesn't enter the second for loop. This is the code:
public void worseFit(int[] array){
int tempPosition = -1;
int tempWeight = 101 ;
for (int x = 0; x < (array.length - 1); x++){
if (allCrates.getSize() < 1){
Crate crate = new Crate();
crate.addWeight(array[0]);
allCrates.add(crate);
} else{
for( int i = 1; i < (allCrates.getSize() - 1); i++ ){
Crate element = allCrates.getElement(i);
int weight = element.getTotalWeight();
if (weight < tempWeight){
tempWeight = weight;
tempPosition = i;
Crate crate = new Crate();
if (weight + tempWeight <= 100){
crate.addWeight(weight + tempWeight);
allCrates.setElement(i, crate);
} else {
crate.addWeight(weight);
allCrates.setElement(allCrates.getSize(), crate);
} // if
} // if
} // for
} // if
} // for
} // worseFit
Once the program enters the else part of the code it goes straight
away back to the beginning of the first for loop.
Would anyone know how to solve this problem?
There seems to be some discrepancies with the expected values of allCrates.getSize().
If allCrates.getSize() returns 2, it will go to the second for loop, but not run it, as i < allCrates.getSize() - 1 will result in false
You might want to use <= instead of <
Initialize the variable i in your second loop to 0 instead of 1. Because if your getSize() returns 1 the it will not enter the if part and after entering the else part the for loop condition will evaluate to false and hence your for loop will not be executed.

else statement not triggering

I have been attempting to create an if else statement that will return a text string based on certain constraints. The first 3 constraints work, but when the event of the final constraint occurs, it triggers the second again. The random number generator occasionally used a 0 value, so I wanted to account for that. I am new to this, and apologize for indenting, etc.
I have been looking around here for a bit and couldn't find anything that seemed to cover this. If I missed it, a hint in the right direction would be appreciated as well.
double txtestimateCategory = [mynum computeVolume];
NSLog(#"The volume is %f", txtestimateCategory);
int v = ((txtestimateCategory * 1));
if ((v >= 8000))
{
NSLog(#"The box is large");
}
else if ((1 <= v < 1000))
{
NSLog(#"The box is small");
}
else if ((1000 <= v < 8000))
{
NSLog(#"The box is medium");
}
else
{
NSLog(#"The box is a lie");
}
Comparators are binary operators. You have to write:
else if (1 <= v && v < 1000)
etc.
(Otherwise you would be evaluating things like true < 1000, and true converts to 1 implicitly. Not what you meant!)