Friday, February 8, 2008

SOCI: Simple Oracle Call Interface

This article introduced a simple C++ database library, SOCI. According to the author, users only need to know two classes, Session and Statement, to complete most of interactions between client programs and database servers.

The following sample, excerpted from the article, demonstrated the simplicity of the library.
  • Session and Statement classes hide OCI calls from the users.
  • Free function use() binds variables to placeholders in the SQL statements.
  • Free function into() populates the variables with the values returned by select statements.
  • Shift operator in the Session enables storing a query and starts creating a temporary object that handles the rest of the expression.
  • Comma operator stores parameter information returned by use and into functions into the temporary object for later use.
  • The temporary object executes the sql statements in its destructor.
#include "soci.h"
#include <iostream>

using namespace std;
using namespace SOCI;

int main()
{
try
{
Session sql("DBNAME", "user", "password");
// example 1. - basic query with one variable used
int count;
sql << "select count(*) from some_table", into(count);
// example 2. - basic query with parameter
int id = 7;
string name;
sql << "select name from person where id = " << id, into(name);
// example 3. - the same, but with input variable
sql << "select name from person where id = :id", into(name), use(id);
// example 4. - statement with no output
id = 8;
name = "John";
sql << "insert into person(id, name) values(:id, :name)", use(id), use(name);
// example 5. - statement used multiple (three) times
Statement st1 = (sql.prepare <<
"insert into country(id, name) values(:id, :name)",
use(id), use(name));
id = 1; name = "France"; st1.execute(1);
id = 2; name = "Germany"; st1.execute(1);
id = 3; name = "Poland"; st1.execute(1);
// example 6. - statement used for fetching many rows
Statement st2 = (sql.prepare << "select name from country", into(name));
st2.execute();
while (st2.fetch())
{
cout << name << '\n';
}
}
catch (exception const &e)
{
cerr << "Error: " << e.what() << '\n';
}
}

Esper: Event Stream Processing and Correlation

I mentioned about Esper before(here). Esper allows users to submit continuous queries to its engine and sends out alerts whenever conditions match user-defined queries. In this article, the authors showed code snippets to demonstrate Esper's usage.
  1. Configure the engine using API or an XML file.
  2. Register continuous queries.
  3. Attach listeners to the queries.
For the engine to tap into event streams, according to the document, it is accomplished by sending events to the engine via the runtime interface.

Esper seems easy to use and, I think, it looks promising to gain popularity.

Monday, January 28, 2008

Using REFCURSOR Bind Variables In Oracle SQL/Plus

I came across this tip here. Here is the output I tried on my machine. Another tutorial is also available in SQL/Plus User Guide.

SQL>
SQL> column owner Format a10;
SQL> column object_id Format 9999;
SQL> column object_type Format a10;
SQL>
SQL> CREATE OR REPLACE PROCEDURE sp_qry_all_object(cur_ds IN OUT SYS_REFCURSOR) AS
2 BEGIN
3 OPEN cur_ds FOR select owner, object_id, object_type from all_objects where object_id<500 and owner='PUBLIC';
4 END;
5 /

Procedure created.

SQL>
SQL> variable cur1 REFCURSOR;
SQL> exec sp_qry_all_object(:cur1);

PL/SQL procedure successfully completed.

SQL> print cur1;

OWNER OBJECT_ID OBJECT_TYP
---------- --------- ----------
PUBLIC 223 SYNONYM
PUBLIC 278 SYNONYM
PUBLIC 272 SYNONYM
PUBLIC 275 SYNONYM

SQL>
SQL> CREATE OR REPLACE FUNCTION sf_qry_all_object RETURN SYS_REFCURSOR
2 AS
3 cur_ds SYS_REFCURSOR;
4 BEGIN
5 OPEN cur_ds FOR select owner, object_id, object_type from all_objects where object_id<500 and owner='PUBLIC';
6 RETURN (cur_ds);
7 END;
8 /

Function created.

SQL>
SQL> variable cur2 REFCURSOR;
SQL> exec :cur2 := sf_qry_all_object;

PL/SQL procedure successfully completed.

SQL> print cur2;

OWNER OBJECT_ID OBJECT_TYP
---------- --------- ----------
PUBLIC 223 SYNONYM
PUBLIC 278 SYNONYM
PUBLIC 272 SYNONYM
PUBLIC 275 SYNONYM

Tips For Boosting .NET WinForm Performance

In this MSDN article, tips were suggested for boosting .NET WinForm Performance and I summarized as follows.
  1. Load fewer modules at startup
  2. Precompile assemblies using NGen
  3. Place strong-named assemblies in the GAC
  4. Avoid base address collisions
    • dumpbin can check the preferred base address of Dlls.
  5. Avoid blocking on the UI thread
  6. Perform lazy processing
    • Some operations can be implemented in the Idle event and will be processed when applications are idle.
  7. Populate controls more quickly
    • The following code snippet shows how to avoid constant repainting.
      listView1.BeginUpdate();
      for(int i = 0; i < 10000; i++)
      {
      ListViewItem listItem = new ListViewItem("Item"+i.ToString() );
      listView1.Items.Add(listItem);
      }
      listView1.EndUpdate();
  8. Exercise more control over data binding
    • BindingSource can help improve performance.
      this.bindingSource1.SuspendBinding();
      for (int i = 0; i < 1000; i++)
      {
      tbl.Rows[0][0] = "suspend row " + i.ToString();
      }
      this.bindingSource1.ResumeBinding();
  9. Reduce repainting
    • Use SuspendLayout method whenever possible to minimize the number of Layout events.
    • Call Invalidate method and pass the area that needs to be repainted as an argument to Invalidate.
  10. Use double buffering
  11. Manage memory usage
    • If controls are added and removed from WinForm dynamically, call Dispose on them. Otherwise, extra unwanted handles would be accumulated in the process.
  12. Use reflection wisely

Thursday, January 24, 2008

Links for 2008-01-24

  • Beautiful Code
    • Chapter 26 - Labor-Saving Architecture: An Object-Oriented Framework for Networked Software :
      • The commonality was achieved by adopting Template Method pattern. That is, common steps in a logging server were defined in the Logging_server base class's run() method, deferring specialization of individual steps of its operation to hook methods in derived classes.
      • The variability was achieved by adopting Wrapper Facade pattern. That is, the variability of semantic and syntactic differences, such as synchronization and IPC mechanisms, was hidden into base classes, such as Acceptor and Mutex . Then using C++ template feature, Logging_server could choose the appropriate Acceptor and Mutex subclasses in a parameterized way.

Saturday, January 5, 2008

ManagedSpy - A Testing Tool For Managed WinForm Applications

ManagedSpy is a tool for access the properties and events of managed windows applications at run time. It's good for debugging or testing Windows Forms controls and is equivalent to Spy++ for unmanaged windows applications.

ManagedSpy is acutally an example demonstrating the usage of ManagedSpyLib. ManagedSpyLib introduced a class, ControlProxy, with which we can get or set properties or subscribe to events of a System.Windows.Forms.Control in another process.

An introduction to ManagedSpy and the internal of ManagedSpyLib can be found in this MSDN article. The following is a testing program listed in the article for testing a WinForm application which has 2 textboxes accepting 2 integers and one button which multiply the 2 integers and shows the product in a third textobx. The lines of code in the blue color use the methods of ControlProxy. As you can see, the testing program programmatically accesses the three textbox controls and one button control in another WinForm program.
private void button1_Click(object sender, EventArgs e)
{
Process[] procs = Process.GetProcessesByName("Multiply");
if (procs.Length != 1) return;
ControlProxy proxy =
ControlProxy.FromHandle(procs[0].MainWindowHandle);
if (proxy == null) return;

//find the controls we are interested in...
if (cbutton1 == null)
{
foreach (ControlProxy child in proxy.Children)
{
if (child.GetComponentName() == "textBox1") {
textBox1 = child;
}
else if (child.GetComponentName() == "textBox2") {
textBox2 = child;
}
else if (child.GetComponentName() == "textBox3") {
textBox3 = child;
}
else if (child.GetComponentName() == "button1") {
cbutton1 = child;
}
}

//sync testchanged on textbox3 so we can tell if it has changed.
textBox1.SetValue("Text", "5");
textBox2.SetValue("Text", "7");
textBox3.SetValue("Text", "");
textBox3.EventFired +=
new ControlProxyEventHandler(textBox3_EventFired);
textBox3.SubscribeEvent("TextChanged");
}
else textBox3.SetValue("Text", "");

//now click on the button to start the test...
if (cbutton1 != null)
{
cbutton1.SendMessage(WM_LBUTTONDOWN, IntPtr.Zero, IntPtr.Zero);
cbutton1.SendMessage(WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
Application.DoEvents();
}

if (result == 35) MessageBox.Show("Passed!");
else MessageBox.Show("Fail!");
}

void textBox3_EventFired(object sender, ProxyEventArgs ed)
{
int val;
if (int.TryParse((string)textBox3.GetValue("Text"), out val)
{
result = val;
}
}

Review Code for Security Defects

In a limited time constraint, what should we look for when reviewing code for security bugs? In this MSDN article, the author suggested to check for the following bugs in code review.

Buffer Overruns in C/C++
void function(char *p) {
char buff[16];
...
strcpy(buff,p);
...
}
When see code like this, trace the variable p back to its source. If it came from an untrusted input, or is not checked for validity close to the point at which it's copied, then it's a security bug.
while (*s != '\\')
*d++ = *s++;
The loop will stop when pointer s hits '\', but pointer d is not checked. The buffer to which pointer d points may be overrun.

Integer Overflows in C/C++
void function(char *b1, size_t c1, char *b2, size_t c2) {
const size_t MAX = 48;
if (c1+c2 > MAX) return;
char *pBuff = new char[MAX];
memcpy(pBuff, b1, c1);
memcpy(pBuff+c1, b2, c2);
}
We may have an integer overflow bug, when the sum of c1 and c2 could exceed the maximum of an integer, i.e., 2^32-1. A rule of thumb is suggested: if you perform a mathematical operation in an expression that is used in a comparison, then you have a potential to overflow and underflow data.

Data Access Code
Don't hard code passwords in connection strings or connect to database using administrative accounts. Also, A database query using string concatenation is a potential security defect and should be fixed by using parameterized queries.

Web Page Code
Hello, <% Response.Write(Request.QueryString("Name")) %>
For code like this, be aware of cross-site scripting issues.

Secrets and Cryptography
Don't store secret data in code, such as passwords and cryptographic keys. Don't create one's own magic cryptographic algorithms, like using an embedded key to XOR a data stream.