and has 0 comments
Here is a song that I found most interesting and I am referring here to the high pitched piano with the distort guitar in the background. The video isn't that exceptional, but watchable. I am trying to imagine a scene of emotional destruction in a movie that would have the particular instrumental part as a soundtrack.



If you want to see the live performance, click here.

Well, it's just as in the AjaxControlToolKit page for the AutoCompleteExtender control. But here is a quick dirty list of the steps:

Option A: (the static page method option)

  1. Add a TextBox to your page
  2. Add the AutoCompleteExtender
  3. Set the ScriptManager property EnablePageMethods to true
  4. Add a static method to the page, one that gets a string and an integer as parameters and returns a string array
  5. Decorate it with [WebMethod(true/false)]. If you set the WebMethod parameter to true, it will have access to the Session
  6. Make sure to return the list of strings depending on the string parameter (which represents what was typed in the TextBox)
  7. Warning! If the method is faulty, you will get no error message, the autocomplete will simply not work.
  8. Warning! Having a different method signature will also cause this to not work.
  9. Set the properties for the AutoCompleteExtender: TargetControlID with the ID of the TextBox, MinimumPrefixLength with the count of typed characters from which to attempt autocomplete, ServiceMethod with the name of the static page method and CompletionInterval with the miliseconds before it attempts autocomplete.

Option B: (the web service option)

  1. Add a TextBox to your page
  2. Add the AutoCompleteExtender
  3. Add a webservice to your web site
  4. The webservice must have [ScriptService] decorating it's class in the codebehind
  5. Add a NOT static method to the webservice, one that gets a string and an integer as parameters and returns a string array
  6. Decorate it with [WebMethod(true/false)] and [ScriptMethod]. If you set the WebMethod parameter to true, it will have access to the Session
  7. Make sure to return the list of strings depending on the string parameter (which represents what was typed in the TextBox)
  8. Warning! If the method is faulty, you will get no error message, the autocomplete will simply not work.
  9. Warning! Having a different method signature will also cause this to not work.
  10. Set the properties for the AutoCompleteExtender: TargetControlID with the ID of the TextBox, MinimumPrefixLength with the count of typed characters from which to attempt autocomplete, ServiceMethod with the name of the WebMethod in the webservice, CompletionInterval with the miliseconds before it attempts autocomplete and ServicePath to the path of the asmx path.


Now it should work.

Code:

//=== AutoComplete.cs - the web service ===
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class AutoComplete : WebService
{

[WebMethod(true)]
[ScriptMethod]
public string[] GetList(string prefixText, int count)
{
string[] arr=new string[] {'list','of','words'};
return arr;
}
}

//=== Web page codebehind
[WebMethod(true)]
[ScriptMethod]
public static string[] GetList(string prefixText, int count)
{
string[] arr=new string[] {'list','of','words'};
return arr;
}


=== Web page ===

<asp:TextBox ID="textboxWithAutoComplete" runat="server">
<cc1:AutoCompleteExtender ID="autoCompleteExtender1" runat="server" TargetControlID="textboxWithAutoComplete"
MinimumPrefixLength="0"
ServiceMethod="GetList"
CompletionInterval="0"
ServicePath="AutoComplete.asmx"
>
</cc1:AutoCompleteExtender>

WARNING! The parameters of the web method must be named prefixText and count or the AutoCompleteExtender will NOT WORK!

A small paragraph that most people miss on the AjaxControlToolKit sample page says: Note that you can replace "GetCompletionList" with a name of your choice, but the return type and parameter name and type must exactly match, including case.

Update (21Th of March 2008): Very important, you need to add the CreateChildControls override in order to work. Otherwise, because of something I can only consider a GridView bug, this will happen: the last page in a mock paging grid will have, let's say, 2 items when the PageSize is 10; on a postback, the number of rows created by the gridview will be 10! even if only 2 have data. Thus, after a postback that doesn't rebind the data in the grid, the GridView.Rows.Count will be PageSize, not the actual bound number.

Update: Recreated the code completely. Now it has both PageIndex and ItemCount.
Also: Actually there is a way to get only the rows that you need in SQL Server 2005. It is a function called Row_Number and that returns the index number of a row based on a certain ordering. Then you can easily filter by it to take items from 20 to 30, for example. In this case, another interesting property of the PagedDataSource is CurrentPageIndex, to set the displayed page number in the pager.

Now, for the actual blog entry.

Why would anyone want to change the PageCount, you ask? Well, assume you have a big big table, like hundreds of thousands of rows, and you want to page it. First you must put it in a DataTable from the SQL server, so that takes time, then the table set a datasource to the GridView, then it implements the paging.

Wouldn't it be nicer to only get the data that you need from the SQL Server, then change the PageCount to show the exact page count that should have been? However, the PageCount property of the GridView is read-only. One quick solution is to get only the data you need, then fill the resulting DataTable with empty rows until you get the real row count. However, adding empty rows to DataTables is excruciatingly slow, so you don't really gain anything, and the Grid works with a big table anyway.

So this is what you do:
First of all determine how much of the data to gather.

Afterwards you need to trick the GridView into creating a Pager that shows the real row count (and possibly page index). Unfortunately you can't do this from outside the GridView. You need to inherit the GridView control and add your stuff inside. After you do this, you need to override the InitializePager method, which is just about the only protected virtual thing related to Paging that you can find in the GridView.

Code:

using System.Web.UI.WebControls;

namespace Siderite.Web.WebControls
{
public class MockPagerGrid : GridView
{
private int? _mockItemCount;
private int? _mockPageIndex;

///<summary>
/// Set it to fool the pager item Count
///</summary>
public int MockItemCount
{
get
{
if (_mockItemCount == null)
{
if (ViewState["MockItemCount"] == null)
MockItemCount = Rows.Count;
else
MockItemCount = (int) ViewState["MockItemCount"];
}
return _mockItemCount.Value;
}
set
{
_mockItemCount = value;
ViewState["MockItemCount"] = value;
}
}

///<summary>
/// Set it to fool the pager page index
///</summary>
public int MockPageIndex
{
get
{
if (_mockPageIndex == null)
{
if (ViewState["MockPageIndex"] == null)
MockPageIndex = PageIndex;
else
MockPageIndex = (int) ViewState["MockPageIndex"];
}
return _mockPageIndex.Value;
}
set
{
_mockPageIndex = value;
ViewState["MockPageIndex"] = value;
}
}

///<summary>
///Initializes the pager row displayed when the paging feature is enabled.
///</summary>
///
///<param name="columnSpan">The number of columns the pager row should span. </param>
///<param name="row">A <see cref="T:System.Web.UI.WebControls.GridViewRow"></see> that represents the pager row to initialize. </param>
///<param name="pagedDataSource">A <see cref="T:System.Web.UI.WebControls.PagedDataSource"></see> that represents the data source. </param>
protected override void InitializePager(GridViewRow row, int columnSpan, PagedDataSource pagedDataSource)
{
if (pagedDataSource.IsPagingEnabled && (MockItemCount != pagedDataSource.VirtualCount))
{
pagedDataSource.AllowCustomPaging = true;
pagedDataSource.VirtualCount = MockItemCount;
pagedDataSource.CurrentPageIndex = MockPageIndex;
}
base.InitializePager(row, columnSpan, pagedDataSource);
}

protected override int CreateChildControls
(System.Collections.IEnumerable dataSource, bool dataBinding)
{
PageIndex = MockPageIndex;
return base.CreateChildControls(dataSource, dataBinding);
}
}
}


What, what, whaaat? What is a PagedDataSource? Inside the GridView, the paging is done with a PagedDataSource, a wrapper around a normal DataSource, which has some of the GridView paging properties like PageSize, PageCount, etc. Even if the PageCount is also a read-only property, you have the AllowCustomPaging property and then the VirtualCount and CurrentPageIndex properties that you can set.

In other words: the pager is initialized at databinding. Set MockItemCount and MockPageIndex before MockPagerGrid.DataBind();

That's it.

Update: People keep asking me to provide a code sample. Let's try together. First, let's see a classic GridView use example:

gridView.DataSource=getDataSource();
gridView.PageIndex=getPageIndex();
gridView.DataBind();
As you can see, we provide a data source programatically, then set the pageindex (let's assume we took it from the URL string) and then call DataBind(). In this situation, we would load the entire data source (say, 10000 rows) then give it to the grid, which would only render something like 20 rows. Very inefficient.

Now, let's replace the original GridView control with the with MockPagerGrid. The code would look like this:

mockPagerGrid.DataSource=getDataSource(2);
mockPagerGrid.MockPageIndex=getPageIndex();
mockPagesGrid.MockItemCount=10000;
mockPagerGrid.DataBind();
This gets the rows for the second page, sets the mock ItemCount and PageIndex to the total number of rows and the page we want and then calls DataBind(). In this situation getDataSource would load only the 20 rows of page 2, would display it, then the pager would show that it is on page 2 out of 500.

This is a very simple example. It assumes you already know the total number of rows returned. A more complete example would look like this:

// starting with an arbitrary page index
var pageIndex=getPageIndex();
// do operations on the database that would return the rows for the page
// with that index, having the size of the page size of the grid
// and also get the total number of rows in the data source
CustomDataSource dataSource=getDataSource(pageIndex,mockPagerGrid.PageSize);
// set the returned rows as the data source
mockPagerGrid.DataSource=dataSource.Rows;
// set the page index
mockPagerGrid.MockPageIndex=pageIndex;
// set the total row count
mockPagesGrid.MockItemCount=dataSource.TotalRowCount;
// databind
mockPagerGrid.DataBind();

// CustomDataSource would only have two properties: Rows and TotalRowCount
// The sql for getDataSource(index,size) would be something like
// SELECT COUNT(*) FROM MyTable -- get the total count
// SELECT * FROM MyTable WHERE RowIndex>=@index*@size
// AND RowIndex<(@index+1)*@size

// for convenience, I assumed that there is a column called RowIndex in
// the table that is set to the row index


Hopefully, this will help people use this code.

and has 0 comments
This is a funny little story about a bunch of low end kids finding a way of letting everyone build whatever electronic device they want for almost free. The lead character is a broker, getting more and more terrified about how this simple thing destroys markets and the capitalist economy. In the end, he is to be replaced by electronic neural networks that perform flawlessly.

It seems Peter Hamilton has some issues with capitalism as there are always some characters criticising it in his books. However, in this particular story, the ending can be only one, where humans are completely replaced by the low cost electronics. It does not destroy communism, it replaces humanity.

My guess is that this is bound to happen sooner or later. Already software glitches are more frequent than hardware ones. When is someone going to realize that we, humans, have the worst hardware possible, even by biological standards. And we're only getting fatter, slower and less efficient by the day. Would I mind being replaced by a race of star faring robotic human replicas? No way.

Well, a timestamp is defined as the integer number of seconds from 1st of January 1970, but not 1st January 1970 itself, that would mean 0 seconds and that is reserved as the 'zero time'.

So, converting is easy in T-Sql (Microsoft Sql Server):
@dateTime=DateAdd(second,{d '1970-01-01'},@timeStamp)
@timeStamp=DateDiff(second,{d '1970-01-01'},@dateTime)

The {d 'yyyy-MM-dd'} notation is an ODBC escape sequence.

and has 2 comments
The Multiline Regex option changes the way "^" and "$" work so that they match the beginning and the end of each line in the input string. Good for quick searches of a string in a list of newline separated strings.

The WriteLine and AppendLine and other .Net text related methods that end in Line append at the end of the input string an Environment.NewLine. This is \r\n in Windows and \n in Linux based systems. But, RegexOptions.Multiline only works on... you guessed it... \n aka new line, ignoring the good old carriage return altogether.

The solutions are: either create the string that contains the lines by adding manually \n and not using *Line, or change the regular expression to something like "^something\r?$".

and has 0 comments
I've just finished reading the book and, while it was the usual easy read, it wasn't as much fun as I expected it to be. The two deaths in the book that were announced so dramatically are actually four, but none of the people that have actually mattered in the story. Their deaths are also irrelevant to the plot.

You see, the entire attraction of Harry Potter, for me, was the many possibilities opened by the magical universe in the books. But really, after the first and second book, there was no novelty, only the drama of Voldemort and the condescending moral crap that was always thrown in the face of the curious reader, the kind of reader that goes "what if..." whenever a new spell is described or some principle of magic is explained.

Bottom line: Harry and the kids wonder in fear and confusion the whole book, only to discover that it all was some kind of master plan and to luckily (or randomly) escape death. The passion killer ending chapter, where Harry is a father of three is not that great either.

I will be watching the 5th Potter movie someday soon, but I believe I will do it for the special effects only. Come to think of it, I can hardly remember what happened in book 5 anyway. Just as the books, only the first two films are worth anything.

I was trying to make a site using a TabContainer and an UpdatePanel and I kept receiving a PageRequestManagerParserErrorException, but only sometimes. A page refresh would fix it and the message looked like "Error parsing near '<html>

<head>

'". The funny thing is that in the Ajax response output I had no <html> or <head>.
Trying desperately a fix detailed in this very nice post: Sys.WebForms.PageRequestManagerParserErrorException - what it is and how to avoid it , mainly forcing the start of a Session when the Page is first loaded, seemed to fix it. (put a if (!IsPostBack) Session["Siderite"]="rules"; in Page_Load)

So beware: the dreaded PageRequestManagerParserErrorException doesn't appear only when the response output is malformed, but apparently also when in some cases someone tries to start a Session from within an async postback.

If you have some other problem linked to this exception, read this post: ASP.Net Ajax and Response.Write or response filters The message received from the server could not be parsed.

and has 0 comments
No comments, just watch.

and has 0 comments
This Hamilton guy is a serious writer, dude! Just having finished the first volume of this story, Pandora's Star, I was blogging desperately about how the scifi writer manages a huge book, with many characters and with colliding story arches. Now, I have finished the second and last part, Judas Unchained, which I personally think is not so good as the first, but still a damn solid scifi.

I did find myself feeling a bit of pleasure seeing how the author fails to escape cliche in the end of the story and the story lines just become accelerated and the actors predictable. But after writing this humongous book, I guess the inner emotions could not be stilled anymore and the ending had to lose some cohesion.

Bottom line: a very good book, one that shows how stories should be written: with a considerate, serious, prolonged effort to give the tale logic as well as create emotion in the soul of the reader. I would have gone for a different ending, but hey, I don't write anymore, I have no right to complain!

and has 0 comments
The historical figure most associated with Dracula, the Wallachian prince Vlad Tepes, had this castle, called Poenari, near Curtea de Arges, and the way to get to it is to climb a 1400 steps stair. Apparently, the Step-Master is also a Romanian invention.

But to start from the beginning: my wife was terribly upset by the 40+ Celsius temperatures in Bucharest. That after telling me so many times that she likes it when it's warm. Now 40C... that's warm for you. But no, she really would have liked to exit the city (for the first time in our new Mitsubishi Colt car) and go to the seaside. The sea being that wet big thing where dirty sweaty people go to dive in while other sweaty dirty people are either stealing their money from the wallets on the beach or stealing their money by selling overpriced bottom of the barrel products and services. Oh, and there is sand there.

So I've convinced her to go to the mountains. Me, in my typical optimism, thinking "the mountains" would be a nice little cool resort like Busteni or Sinaia or Predeal, where climbing the mountain is synonymous with walking the mountain. But no, she wanted Poenari, Dracula's bloody castle.

So we've spent 4 hours getting there, the Colt performed admirably and the air conditioning system made my day. Then I was informed that seeing the castle involved the inhuman endeavour of walking The Stairs to Hell. Well, I ride a bike, 1400 steps is like... 100 floors in a bloc of flats. How hard can that be?

After 15 minutes of pure agony while my body was producing my own private sea water version and trying to reach the top by filling the mountain valley and floating me up, we reached the castle. Which is a damn ruin of a castle, with no people getting you water or food or anything. There was one guy, though, who was kind enough to charge us for the privilege to see the castle and had his own private stash of aspirin to counteract the thermal shock of going from a 19C air conditioned car to a 35C stair climb.

Vlad Tepes Dracula has had his revenge and keeps on having it. Somewhere in his grave, the body of this usually negative person must be grinning.

and has 0 comments
A Perfect Circle has the same lead man as Tool, James Maynard. As far as I see they do really nice lyrics and music. Personally I preferred the cover of John Lennon's song Imagine, but I couldn't find the video for it in all the anime+9/11+Iraq war home made video crap that clogs YouTube.

Check out Judith, which was inspired by the illness of the singer's mother, paralysed in bed, but still praying and thanking Christ. Although if you want to see anything and witness Maynard's weirdness, check out this video of a live TV appearance.


Update: The 30 September 2009 release of the AjaxControlToolkit doesn't have the error that I fix here. My patch was applied in July and from September on the bug is gone in the official release as well. Good riddance! :)

==== Obsolete post follows

Update: On June 20th 2009, Codeplex notified me that the patch I did for the ACT has been applied. I haven't tested it yet, though. Get the latest source (not latest stable version) and you should be fine.

This post was updated on the 1st of July 2008 with some clearer explanations and some error corrections thanks to Santoé who pointed out some mistakes.

My ASP.Net app uses a TabContainer, with a TabPanel in the *x code and with additional TabPanels added dynamically in codebehind.

Well, I got a lot of errors so I've decided to debug and change the control in order to fix it.

Step 1: download the AjaxControlToolKit with source included and open the project locally.

First error : Specified argument was out of the range of valid values. Parameter name: index, somewhere in the TabPanelCollection indexer. The problem actually occurs in TabContainer in LoadClientState(string clientState) where there is a for (int i = 0; i < tabState.Length ; i++). It doesn't take into account the possibility that the number of Tabs and the number of values taken from the tabState can be different. So the code must look like this: for (int i = 0; i < tabState.Length && i < Tabs.Count; i++).

Step 2: In the AjaxControlToolkit\AjaxControlToolkit\Tabs\ folder there is a TabContainer.cs file. Change for (int i = 0; i < tabState.Length ; i++) to for (int i = 0; i < tabState.Length && i < Tabs.Count; i++).

The second error is actually a thrown error in the ActiveTabIndex property setter: if (value >= Tabs.Count) { throw new ArgumentOutOfRangeException("value"); }, but it all comes from this: if (Tabs.Count==0 && !_initialized), because it doesn't take into account the possibility that the Tabs.Count is smaller than the ActiveTabIndex, but not zero. So that should look like this: if (value >= Tabs.Count && !_initialized).

I've downloaded the latest AjaxControlToolKit (version Version 1.0.20229 - Feb 29 2008) and the scratched fix above doesn't seem to work anymore. Instead, try patching the ActiveTabIndex property like this:

[DefaultValue(-1)]
[Category("Behavior")]
[ExtenderControlProperty]
[ClientPropertyName("activeTabIndex")]
public virtual int ActiveTabIndex
{
get
{
if (_cachedActiveTabIndex > -1)
{
return _cachedActiveTabIndex;
}
if (Tabs.Count == 0)
{
return -1;
}
return _activeTabIndex;
}
set
{
if (value < -1)
throw new ArgumentOutOfRangeException("value");
if (Tabs.Count == 0 && !_initialized)
{
_cachedActiveTabIndex = value;
}
else
{
if (ActiveTabIndex != value)
{
if (ActiveTabIndex != -1
&& ActiveTabIndex < Tabs.Count)
{
Tabs[ActiveTabIndex].Active = false;
}
if (value >= Tabs.Count)
{
_activeTabIndex = Tabs.Count-1;
_cachedActiveTabIndex = value;
}
else
{
_activeTabIndex = value;
_cachedActiveTabIndex = -1;
}
if (ActiveTabIndex != -1
&& ActiveTabIndex < Tabs.Count)
{
Tabs[ActiveTabIndex].Active = true;
}
}
}
}
}


In other words, remove the ArgumentException code block and move the condition inside the next block, where you set the real _activeTabIndex to the highest legal value, yet you put the real value in _cachedActiveTabIndex.

Step 3: in the AjaxControlToolkit\AjaxControlToolkit\Tabs\ folder there is a TabContainer.cs file. Change the ActiveTabIndex property with the code above.

The same thing must be done in Javascript, in the Tabs.js file, if you intend to use a TabContainer with no static tabs defined. In case you do that, you will get a javascript error "Microsoft JScript runtime error: Sys.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: value
". The fix is to change the set_activeTabIndex function of the TabContainer in the file tabs.js to this:
set_activeTabIndex : function(value) {
if (!this.get_isInitialized()) {
this._cachedActiveTabIndex = value;
} else {
if (this._activeTabIndex != -1) {
this.get_tabs()[this._activeTabIndex]._set_active(false);
}
if (value < -1 || value >= this.get_tabs().length) {
this._activeTabIndex = this.get_tabs().length-1;
this._cachedActiveTabIndex=value;
} else {
this._activeTabIndex = value;
this._cachedActiveTabIndex=-1;
}
if (this._activeTabIndex != -1) {
this.get_tabs()[this._activeTabIndex]._set_active(true);
}
if (this._loaded) {
this.raiseActiveTabChanged();
}
this.raisePropertyChanged("activeTabIndex");
}
},


Step 4: in the AjaxControlToolkit\AjaxControlToolkit\Tabs\ folder there is a tabs.js file. Change the set_activeTabIndex function with the code above.

This fixed it for me for now.

Step 5: Compile the now patched AjaxControlToolKit and use the resulting dll in your project instead of the default one.

As a reference, my test app does the following things:
  • Starts with a TabContainer with single TabPanel defined in the aspx
  • Has a button that adds new tabs to the TabContainer dynamically on the Click event
  • The panels have buttons in them that can be clicked
  • The active tab must be preserved during postbacks
  • The page must work both on synchronous and asynchronous postbacks


Here is the code for the page

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using AjaxControlToolkit;

public partial class _Default : Page
{
private int? _tabCount;

/// <summary>
/// Keep in ViewState the number of dynamically added tabs
/// </summary>
public int TabCount
{
get
{
if (_tabCount == null)
{
if (ViewState["TabCount"] == null)
TabCount = 0;
else
TabCount = (int) ViewState["TabCount"];
}
return _tabCount.Value;
}
set
{
_tabCount = value;
ViewState["TabCount"] = value;
}
}

protected void Page_Load(object sender, EventArgs e)
{
InitTabs();
}

/// <summary>
/// Add the dynamical tabs after each postback
/// </summary>
private void InitTabs()
{
for (int c = 0; c < TabCount; c++)
AddPanel();
}

/// <summary>
/// Dynamically add a panel to the TabContainer
/// </summary>
private void AddPanel()
{
TabPanel tp = new TabPanel();
tp.HeaderText = "Test Dinamic";
TextBox tb = new TextBox();
Button btn = new Button();
btn.Text = "Click me!";
tp.Controls.Add(btn);
tp.Controls.Add(tb);
TabContainer1.Tabs.Add(tp);
}

/// <summary>
/// Click event to add a new panel
/// and update the TabCount property
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void btnAddPanel_Click(object sender, EventArgs e)
{
AddPanel();
// do this if you didn't have any staticly defined
// tabs or else the dynamic tabs will be invisible
If (TabCount==0) TabContainer1.ActiveTabIndex=0;
TabCount++;
}
}

and has 0 comments
A while ago I was recommending you the female vocalist band theStart. They have released another album, entitled Ciao, Baby. Go to their mySpace page to listen to four of the ten tracks on the album or buy the tracks directly, 1$ each.


It seems to me that the band is moving away from rock and going towards electro-pop, which would suck, but the songs are still nice.

In order to debug SQL many people open new windows in Query Analyser or Management Studio trying to see where the errors come from and opening transactions and rolling them back and basically be miserable.

Yet, even from Microsoft SQL 2000 stored procedures had debug support. You would use Query Analyser, open Object Browser, right click a stored procedure and select Debug.

However, in SQL 2005 you can't do that anymore. Query Analyser is no longer available, the Management Studio doesn't have debug options and the SQL 2000 Query Analyser doesn't allow you to debug stored procedures on SQL 2005 servers. But there is support for SQL debugging in Visual Studio .NET, in the Professional and Team versions. Let me rephrase: If you have the Express or Standard editions you are out of luck. No SQL 2005 debugging for you. I did some queries on the web searching for third party sql debuggers, maybe something from Microsoft, like their Javascript Debugger (which works better than the in-built javascript debugging in Visual Studio, btw)

There are some ugly problems that may occur:

Maybe others. In this case, please let me know so I can update the post. Other people need help too, you know?

Even so, SQL debugging is not as straight forward as usual debugging. From the Microsoft entry on How to debug stored procedures in Visual Studio .NET I quote the Limitations of stored procedure debugging:
  • You cannot "break" execution.
  • You cannot "edit and continue."
  • You cannot change the order of statement execution.
  • Although you can change the value of variables, your changes may not take effect because the variable values are cached.
  • Output from the SQL PRINT statement is not displayed