This is an advanced sequel to C#: Enums and Strings Are Friends. One of particularly interesting features of an enum is the possibility of extending its values with attributes.
public enum Digits
{
[Arabic("1")]
[Roman("I")]
One=1,
[Arabic("2")]
[Roman("II")]
Two,
[Arabic("3")]
[Roman("III")]
Three
}
These values can be obtained using .NET reflection mechanism. .NET already defines a lot of useful attributes such as Description, DisplayName, DefaultValue.On top of that you are able to derive your custom attributes from the Attribute class. By adding properties to this class you can attach a plethora of information to each value of an enum.
[AttributeUsage(AttributeTargets.Field)]
public class RomanAttribute : Attribute
{
private readonly string _digit;
public string Digit
{
get { return _digit; }
}
public RomanAttribute(string title) // url is a positional parameter
{
_digit = title;
}
}
Wouldn't it be nice if we could read value of any property of any attribute straight off enum value? The problem with this concept is ... properties of different attributes have different names. For example: DescriptionAttribute has property named Description, and DisplayNameAttribute has property named DisplayName.Luckily we live in the age of generics and reflections. So reading these properties no longer requires hard coded attribute type and target property. You can simply pass attribute type, property type, property name and enum to a function and let reflection do its business.
// Read [Description] attribute.
Enum e = Days.Sat;
string s = e.GetAttributeProperty<DescriptionAttribute, string>("Description");
Console.WriteLine("Description is {0}", s);
// Read [DisplayName ] attribute.
s = e.GetAttributeProperty<DisplayNameAttribute, string>("DisplayName");
Console.WriteLine("Display name is {0}", s);
// Find enum value based on [Description].
Enum ef = e.FindEnumValueByAttributeProperty<DescriptionAttribute, string>("Description","Friday");
All that is left is to write these two conversion functions.
public static class EnumEx
{
#region Enum Extensions
public static PT GetAttributeProperty<AT, PT>(this Enum this_, string propertyName)
where AT : Attribute
where PT : class
{
// First get all attributes of type A.
AT[] attributes =
(this_.GetType().GetField(this_.ToString())).GetCustomAttributes(typeof(AT), false) as AT[];
if (attributes == null || attributes.Length == 0) // Null or can't cast?
return null;
else
{ // We have something.
AT a = attributes[0];
PropertyInfo pi = a.GetType().GetProperty(propertyName);
if (pi != null)
{
PT result = pi.GetValue(a, null) as PT;
return result;
}
else
return null;
}
}
public static Enum FindEnumValueByAttributeProperty<AT, PT>(this Enum this_, string propertyName, PT propertyValue)
where AT : Attribute
where PT : class, IComparable
{
// First get all enum values.
Array enums = Enum.GetValues(this_.GetType());
foreach (Enum e in enums)
{
PT p = e.GetAttributeProperty<AT, PT>(propertyName);
if (p!=null && p.Equals(propertyValue))
return e;
}
return null;
}
#endregion // Enum Extensions
}
UPDATE: It seems like the usage of < and > symbols in code corrupted the listings. Fixed it.
If you need a portable .NET solution for converting RGB to HLS and vice versa there are libraries around to do it. For Windows only using the Shell Lightweight Utility Functions is a simpler alternative.
[DllImport("shlwapi.dll")]
static extern int ColorHLSToRGB(int H, int L, int S);
[DllImport("shlwapi.dll")]
static extern void ColorRGBToHLS(int RGB, ref int H, ref int L, ref int S);
// RGB2HLS
ColorRGBToHLS(ColorTranslator.ToWin32(rgbColor, ref h, ref l, ref s);
// HLS2RGB
Color rgbColor=ColorTranslator.FromWin32(ColorHLSToRGB(h, l, s));
Many thanks to John Boker for his concise explanation. What a time saver.
"Margin is on the outside of block elements while padding is on the inside. Use margin to separate the block from things outside it, padding to move the contents away from the edges of the block."
Sometimes you want a function to return an object or null if no object is found. Lazy evaluation makes it easy to automate this behaviour.
public Person FindPerson(Criteria c)
{
Lazy<Person> person = new Lazy<Person>();
// Code to actually find a person ...
// ... and populate person.Value
return person.IsValueCreated ? person.Value : null;
}This is fairly ellegant. If no person is found lazy evaluation assures that the object is never created and related resources are not spent. Be careful though! Here's a common pest.foreach (Font font in GetFixedFonts())
{
// But GetFixedFonts returned null.
}The fictional GetFixedFonts() function called in code bellow returns Font[] collection. You assume it will always return a non- null value. But then on a bad day it doesn't and your code breaks with an exception.You can assure that function always returns an array /even if empty/ by using lazy evaluation too. Here is an example of that.
public FontFamily[] GetFixedFonts()
{
Lazy<List<FontFamily>> fonts = new Lazy<List<FontFamily>>();
foreach (FontFamily ff in System.Drawing.FontFamily.Families)
if (IsFixedFontFamily(ff))
fonts.Value.Add(ff);
return fonts.Value.ToArray();
}
You know the drill. Programming a graph takes too much time...use a library...or hire an external consultant. But...is it really so?
Imagine you have two coordinate systems. Your physical screen coordinate system spans from 0 to window's width horizontally and from 0 to window's height vertically. And your imaginary world (i.e. a map) spans from -10.000 to 10.000 horizontally and from 0 to 5000 vertically.
Just to make things a bit more complex you also want to:
- zoom everything on the screen by arbitrary zoom factor, and
- show only part of your map on the screen starting from point T(-3.000, 1000) given in map coordinates, where -3000 is left and 1000 is top coordinate of part of map we would like to display on screen.>
Map to Screen
Are you scared yet? Don’t be. Here is the basic formula for converting map coordinate to screen coordinate:

Same formula can be applied to another dimension. For example:

So far ... so trivial. :) Since you start at point T(x,y) you need to put x and y to point to 0,0 on the screen. Afterwards you simply multiply by zoom factor. If factor is 1 then 1 point on the map is converted to 1 point on the screen. If the factor is 1:2 then 1 point on the map is only ½ point on the screen. And so on.
If the axis is a reverse axis then your equation is:

Screen to Map
What if somebody clicks on the screen and we need to find map coordinate of the click? Let us derive this scenario from the above equation:

Deriving same formula for the reverse axis is a good exercise for you, don’t you agree? :)
Fit to Screen
If we want to fit our map inside the screen we must start drawing it at its T=T0 point. We calculate T by using:

No big secrets here. So our left, right point T is at map's min x and min y. And if reverse axis is being used we must use max instead.
The apropriate fit to screen zoom is calculated like this:

If you are using same unit for both axes then there will be only one zoom factor. To still fit map to the screen make sure that you fit larger dimension of both - width or height to fit the screen. Then use the same zoom factor for smaller dimension. This way both are guaranteed to fit the screen.
Calculate Distances
Last but not least ... distances are calculated with a little help from previous calculations. If you have a distance in screen units and you would like to convert to map distance you subtract it from point zero and derive the formula like this:

The distance obviously depends on the zoom factor alone. For better understanding derive the opposite formula and get screen distance from map distance yourself. :)
Coming Next...
So there you have it. Most of these formulas are -in fact- just simplified 4 x 4 matrix translation, usually performed for you by modern 2D graphics engines such as GDI+ or Cairo.
Observing simplicity of graph math one realizes that graphs aren't really such a terrible development effort. It's drawing points, lines and polygons using these formulas to translate coordinates. Zooming is changing the zoom factor, and scrolling is changing the T point. We will take a closer look at these operations in part two of this series.
A singleton is like the Egg of Columbus. Easy after someone had showed you how to do it. Luckily Jon Skeet had showed us how to use lazy evaluation for thread safety. And an unknown contributor of Great Maps had demonstrated the usage of generics for that purpose. So all that is left for me - is to put it all together.
public sealed class Singleton<T> where T : new()
{
private static readonly Lazy<T> instance = new Lazy<T>(() => new T());
public static T Instance { get { return instance.Value; } }
private Singleton()
{
}
}
// Create two server objects pointing to the same instance.
Server svr1 = Singleton<Server>.Instance;
Server svr2 = Singleton<Server>.Instance;
Reference:- C# In Depth: Implementing the Singleton Pattern in C#
- GMap.NET Singleton Class
So you needed to draw a grid … or a ruler … or another x-y-ish vector graphics and you ended up with code snippets like this everywhere:
public void Grid(Graphics g, Size size, int step) {
for (int i = 0; i < size.Width; i+=step)
{
g.DrawLine(Pens.Black,
new Point(i, 0),
new Point(i, size.Height)
);
}
for (int i = 0; i < _size.Height; i += step)
{
g.DrawLine(Pens.Black,
new Point(0, i),
new Point(size.Width, i)
);
}
}
You can avoid redundancy in such situations by using the strategy pattern. First create a new interface called IDirection.
public interface IDirection
{
int GetMoving(Size size);
int GetStatic(Size size);
void AddMoving(ref int x, ref int y, int step);
Point GetPoint(int moving, int static_);
}
Now imagine yourself free- falling into a deep hole. Remember, you are a programmer. So stop screaming and start thinking about the fall. Your moving direction is vertical. And since you are in a vertical free- fall you almost don’t move in x direction. Therefore your static direction is horizontal. Now write this in code.
public class VerticalDirection : IDirection
{
public int GetMoving(Size size)
{
return size.Height;
}
public void AddMoving(ref int x, ref int y, int step)
{
y += step;
}
public Point GetPoint(int moving, int fixed_)
{
return new Point(fixed_, moving);
}
public int GetStatic(Size size)
{
return size.Width;
}
}
And a HorizontalDirection class.
class HorizontalDirection : IDirection
{
public int GetMoving(System.Drawing.Size size)
{
return size.Width;
}
public void AddMoving(ref int x, ref int y, int step)
{
x += step;
}
public Point GetPoint(int moving, int fixed_)
{
return new Point(moving, fixed_);
}
public int GetStatic(Size size)
{
return size.Height;
}
}
There we go. Static and moving direction for each concrete direction class are encapsulated and we can now write new grid drawing code.
public void Grid(Graphics g, Size size, int step)
{
Grid(g, size, step, new VerticalDirection());
Grid(g, size, step, new HorizontalDirection());
}
public void Grid(Graphics g, Size size, int step, IDirection direction)
{
for (int i = 0; i < direction.GetMoving(size); i += step)
{
g.DrawLine(Pens.Black,
direction.GetPoint(i, 0),
direction.GetPoint(i, direction.GetStatic(size))
);
}
}
Sometimes you want to know index of the minimal value of an array. I’ve frequently seen programmers using two data structures to accomplish this task: one to hold the index and the other to hold the value (i.e. current minimum) while iterating. Unless you need to optimize your code for speed you really only need an integer for this task.
int find_min(int* vals, int len)
{
int mindx= 0;
for (int i = 1; i < len; i++)
if (vals[i] < vals[mindx]) mindx= i;
return mindx;
}
Categories culture , zx spectrum
GNU Make is a decent tool. But due to the fact that I commonly create only a handful of Makefiles per project and that its syntax is easy to forget (or -perhaps- hard to remember) - it often takes me an hour before I create a new generic Makefile for a project.
More often then not I end up analysing and recycling an existing one from one of my previous projects. Thus I wrote a generic Windows starter that will work on any folder that contains .c and .h files as long as you have The GNU C Compiler Suite and Make installed on your machine.
Simply add this Makefile to your folder and change the target (the default is "buddy.exe") to the name of your desired exe output file. Make sure that one .c file contains the main function and the rest will be done by the build system.
The main tricks being used are:
1. Obtaining list of all *.c files in folder...
SRCS = $(wildcard *.c)2. ...using it to generate all object files.
OBJS = $(patsubst %.c,%.o,$(SRCS))3. Creating dependency file named .depend by using -MM switch on gcc (i.e. fake compilation step).
$(CC) $(CFLAGS) $(SRCS) -MM >> .depend4. Including dependency file into makefile using -include (minus means it will not complain if the file is not there i.e. on the first run).
-include .depend5. And last but not least: redirection of stderr to NUL to prevent DEL command from complaining when there are no matching files.
del *.o 2>NULHere is the entire Makefile.
Categories c , c++ , compilation , gnu , make
Following step-by-step instructions by Adam J. Kunen I was able to compile my own gnu arm tool-chain on Ubuntu Linux 12.10.
I used following packages:
- binutils-2.23
- gcc-4.8.1 (Adam also recommends downloading packages gcc-core and g++ but I skipped those)
- gdb-7.6
- newlib-2.0.0
../../src/gcc-4.8.1/configure --target=arm-none-eabi --prefix=$MYTOOLS --enable-interwork --enable-multilib --enable-languages="c,c++" --with-newlib --with-headers=../../src/newlib-2.0.0/newlib/libc/include --with-system-zlib
UPDATE: Unfortunately this fix has some issues. It will not build libgcc. Seeking for a better solution.
Categories arm , c++ , compilation , embedded , gnu
This is a little pet project of mine. It provides me with sort of in-depth understanding of embedded designs, programming languages and operating systems that only a hands-on approach can.
Categories architectures , compilation , gnu , threads , unix , zx spectrum
A picture is worth a thousand words.
Source: Dr. Dobb's Journal
Mapping database tables to C++ classes is a common challenge. Let us try to map a database table person to a class.
using namespace boost::gregorian;
using namespace std::string;
class person {
public:
string first_name;
string last_name;
date date_of_birth;
int height;
float weight;
};
Under perfect conditions this would work just fine. But in practice when rolling out our database layer (with elements of RDBMS-2-OO) several problems arise. One of them is handing null values.
In C# we would use (...and strongly typed datasets do) nullable types.
public class Person {
public:
string FirstName;
string LastName;
date DateOfBirth;
int? Height; // Nullable type.
float? Weight; // Nullable type.
};
However there is no similar language construct in C++. So we will have to create it. Our todays' goal is to add built in value types the ability to be null. And to be able to detect when they are null.
We will create new types but we desire -just like in C#- that they behave like existing built in types.
So why not deriving from built in types?
class int_ex : int {
}
I've been thinking long and hard about the appropriate answer to this good question. And finally I came up with the perfect argument why this is a bad idea. It's because it won't compile.
Luckily we have templates. Let us start by declaring our class having a simple copy constructor.
template <typename T>
class nullable {
private:
T _value;
public:
// Copy constructor.
nullable<T>(T value) {
_value=value;
}
};
With this code we have wrapped built in value type into a template. Let us explore possibilities of this new type.
int n=10;
nullable<int> i=20; // This actually works!
nullable<int> j=n; // This too.
nullable<int> m; // This fails because we have no default constructor.
This is a good start. Since we have not defined a default constructor and we have defined a copy constructor the compiler hasn't generated the default constructor for us. Thus last line won't compile. Adding the default constructor will fix this. The behavior of the ctor will be to make value type equal to null. For this we will also add _is_null member to our class. Last but not least we will add assignment operator to the class.
template <typename T>
class nullable {
private:
T _value;
bool _is_null;
public:
// Copy ctor.
nullable<T>(T value) {
_value=value;
_is_null=false;
}
// Default ctor.
nullable<T>() {
_is_null=true;
}
// Assignment operator =
nullable<T>& operator=(const nullable<T>& that) {
if (that._is_null) // Make sure null value stays null.
_is_null=true;
else {
_value=that._value;
_is_null=false;
}
return *this;
}
};
Now we can do even more things to our class.
int n=10;
nullable<int> i=20; // Works. Uses copy constructor.
nullable<int> j; // Works. Uses default ctor. j is null.
j=n; // Works. Uses copy constructor + assignment operator.
j=i; // Works. Uses assignment operator.
Next we would like to add the ability to assign a special value null to variables of our nullable type. We will use a trick to achieve this. We will first create a special type to differentiate nulls' type from all other types. Then we will add another copy constructor further specializing template the null type.
class nulltype {
};
static nulltype null;
template <typename T>
class nullable {
private:
T _value;
bool _is_null;
public:
// Assigning null.
nullable<T>(nulltype& dummy) {
_is_null=true;
}
// Copy ctor.
nullable<T>(T value) {
_value=value;
_is_null=false;
}
// Default ctor.
nullable<T>() {
_is_null=true;
}
// Assignment operator =
nullable<T>& operator=(const nullable<T>& that) {
if (that._is_null) // Make sure null value stays null.
_is_null=true;
else {
_value=that._value;
_is_null=false;
}
return *this;
}
};
Let us further torture our new type.
nullable<int>m=100; // Works! m=100!
nullable<int>j; // Works! j is null.
nullable<int>n=j=m; // Works! All values are 100.
nullable<int>i=null; // Works! i is null.
Our type is starting to look like a built in type. However we still can't use it in expressions to replace normal value type. So let's do something really dirty. Let us add a cast operator into type provided as template argument.
// Cast operator.
operator T() {
if (!_is_null)
return _val;
}
Automatic casts are nice and they work under perfect conditions. But what if the value of nullable type is null? We'll test for the null condition in our cast operator and throw a null_exception.
Throwing an exception is an act of brutality. We would like to allow user to gracefully test our type for null value without throwing the exception. For this we will also add is_null() function to our class.
class null_exception : public std::exception {
};
class null_type {
};
static null_type null;
template <typename T>
class nullable {
private:
T _value;
bool _is_null;
public:
// Assigning null.
nullable<T>(null_type& dummy) {
_is_null=true;
}
// Copy ctor.
nullable<T>(T value) {
_value=value;
_is_null=false;
}
// Default ctor.
nullable<T>() {
_is_null=true;
}
// Assignment operator =
nullable<T>& operator=(const nullable<T>& that) {
if (that._is_null) // Make sure null value stays null.
_is_null=true;
else {
_value=that._value;
_is_null=false;
}
return *this;
}
// Cast operator.
operator T() {
if (!_is_null)
return _value;
else
throw (new null_exception);
}
// Test value for null.
bool is_null() {
return _is_null;
}
};
We're almost there. Now the following code will now work with new nullable type.
nullable<int> i; // i is null
nullable<int> j=10;
i=2*j; // i and j behave like integer types.
j=null; // you can assign null to nullable type
if (j.is_null()) { // you can check j
int n=j+1; // Will throw null_exception because j is null
}
There are still situations in which nullable types do not act or behave like the built in value types.
// This will fail...
for(nullable<int> i=0; i<10;i++) {
}
To fix this we need to implement our own ++ operator.
// Operator ++ and --
nullable<T>& operator++() {
if (!_is_null) {
_value++;
return (*this);
} else
throw (new null_exception);
}
nullable<T> operator++(int) {
if (!_is_null) {
nullable<T> temp=*this;
++(*this);
return temp;
} else
throw (new null_exception);
}
This is it. We have developed this type to a point where it serves our purpose. To enable us to write database layer.
using namespace boost::gregorian;
using namespace std::string;
class person {
public:
string first_name;
string last_name;
date date_of_birth;
nullable<int> height;
nullable<float> weight;
};
There's still work to be done. Implementing remaining operators (such as ==). Finding new flaws and differences between our type and built in types. I leave all that to you, dear reader. If you extend the class please share your extensions in the comments section for others to use. Thank you.
Categories c++ , compilation , patterns
I expected most of my readership to come from Africa, India and Asia. But they are from Silicon Valley, California.
I have always wanted to know how ./configure does its magic. To a Gnu newbie the Gnu Build System seems utterly complex. Available manuals for Autoconf, Automake and Libtool are several hundred pages of difficult-to-read text. Learning curve is steep. Way too steep to produce a simple script!
But then -last week as I googled around- I found these gems:
- Using Automake and Autoconf with C++
- Using C/C++ libraries with Automake and Autoconf
- Building C/C++ libraries with Automake and Autoconf
These make understanding basic path of execution much easier and are an excellent pre-read before feeding your brain with official manuals.
Categories c++ , compilation , gnu , tools
Categories c++ , compilation , gnu , tools
Coming from Windows background I was a bit worried about the complexity of accessing Postgres databases from C++. I'm still having nightmares of early ODBC programming back in the 90ties. But as a mature developer I quickly overcame Microsoft's fixation on building the mother of all DBMS access technologies; that is - a common database mechanism to access various DBMSes.
Seriously, how many times in life have you ported a database from MS SQL Server to Oracle? There is a brilliang library for accessing Postgres (and only Postgres!) from C++ available. It is pqxx. It comes with a tutorial to help you getting started.
Here is Hello World of libpqxx. It doesn't get any simpler then that. Following code executes a query on a database.
#include <pqxx/pqxx>
using namespace pqxx;
void execute_query() {
connection cn("dbname=my_database");
work w(cn, "mytransaction");
w.exec("INSERT INTO city(city_name) VALUES ('Ljubljana');");
w.commit();
}
And now for something a bit more complex. Today we're going to discover the art of creating a stored procedure / function layer in Postgres database.
Let us first agree on terminology. In Postgres there is no difference between a stored procedure and a function. A procedure is merely a function returning void. Thus from now on we will only use term function.
Just in case you wonder - as a mature DBMS Postgres prepares (precompiles) all functions for optimal performance, exactly as its commercial competitors.In contemporary databases functions are commonly used to implement security layer. It is generally easier to give a user permission to execute a function that manipulates many database tables to complete a business operation then it is to assign him or her just the right permissions on all involved database tables for the same result.
Therefore modern designs introduce an additional layer of abstraction to access database tables. This layer is implemented via functions. In such scenario users can access database tables only through functions. They have no direct access to database tables.

To implement this design we need to know more about the Security of definer concept.
Security of definer
In Postgres a function can be defined to have “Security of definer” property set. You can set this propety in pgAdmin (see the screenshot bellow).

To set this property manually add SECURITY DEFINER to the end of function definition like this -
CREATE FUNCTION insert_city(character varying)
RETURNS void AS
$BODY$
BEGIN
INSERT INTO city("name") VALUES($1);
END
$BODY$
LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;
Adding this to a function will make it run under the context of the owner of the function instead of context of the caller of the function. This allows a user to insert city into a table without having insert permission on it. As long as he has permission to execute this function and the owner of the function has permission to insert into city table. It is a way to implement chained security on Postgres.
Postgres functions that return datasets
Postgres functions that return data sets are poorly documented and their syntax might look a bit awkward to those of you used to SQL Server. When a function in Postgres returns multiple results it must be declared to return SETOF some type. Call syntax for such functions is a bit different then what you are used to. You call it using SELECT * FROM function() instead of usual SELECT function() call.
SELECT function_returning_setof(); -- Wrong!
SELECT * FROM function_returning_setop(); -- OK!
SELECT function_returning_scalar(); -- OK
Let's imagine we have a table of all cities with two fields – city_id of type SERIAL, and name of type VARCHAR(80). Actually we're imagining this througout this article.
Here is a code fragment showing how to write a function returning all cities.
CREATE FUNCTION list_all_cities()
RETURNS SETOF city AS
$$
DECLARE
rec record;
BEGIN
FOR rec IN (SELECT * FROM city) LOOP
RETURN NEXT rec;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- Call the function.
SELECT * FROM list_all_cities();
This code is using generic type called RECORD. Try experimenting with %ROWTYPE to obtain same results. Function above returns type SETOF city - each record in the set has the same structure as a record of city table. But what if you wanted to return another structure? One way is to create a type like this -
CREATE TYPE list_all_city_names_result_type AS (city_name varchar(80));
CREATE FUNCTION list_all_city_names()
RETURNS SETOF list_all_city_names_result_type AS
$$
DECLARE
rec record;
BEGIN
FOR rec IN (SELECT "name" FROM city) LOOP
RETURN NEXT rec;
END LOOP;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM list_all_city_names();
If this imposes too harsh limitations then you can also use the generic RECORD data type as return type and tell the procedure what to expect when calling it.
CREATE FUNCTION list_all_city_names2()
RETURNS SETOF RECORD AS
$$
DECLARE
rec record;
BEGIN
FOR rec IN (SELECT "name" FROM city) LOOP
RETURN NEXT rec;
END LOOP;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM list_all_city_names2()
AS ("city_name" varchar(80)); -- Expect varchar(80)
There's one more trick. I don't recommend it but I'm publishing it anyways. If you'd like to make things really simple for you then you could use another language instead of plpgsql. For example, using sql code you can write queries directly into your function like this -
CREATE FUNCTION getallzipcodes()
RETURNS SETOF zip AS
$BODY$
SELECT * FROM zip;
$BODY$
LANGUAGE 'sql';
Stored procedure layer and automatic code generation
When I create stored procedure layer I like to generate code for basic CRUD functions. I only write code for complex business functions by hand. Thus in my next article I am going to write code generator to do just that for Postgres/c++ pair.
But right now let's just explain some concepts. CRUD functions are - Create (new record from data), Read (given ID), Update (existing record given ID and new data) and Delete (given id) for single table. These functions are needed for every table. For example for table city you would have following functions:
- create_city(name),
- read_city(id),
- update_city(id,new_name),
- delete_city(id).
Two more types of functions are often needed. Get functions and list functions (sometimes called find functions). The difference between get and list function is that a get function always return single result. For example get_city_id_by_name(name) or get_user_by_phone(phone). Whereas list function returns all records that match the condition provided as parameters. For example - list_cities_starting_with(word) or list_persons_older_then(age) or list_all_countries().
Some people prefer list_ and other prefer find_ prefix for list functions. It is a matter of taste; as long as your programming stlye is consistent.
Table above shows functions that will be needed for almost any table and are therefore candidates for automatic code generation. We'll deal with code generation in one of our following articles.
Categories architectures , patterns , postgres , sql
If you would like to publish SQL or C++ code on your blog hosted by Blogger I recommend SyntaxHighlighter.
You can install the SyntaxHighlighter Blogger widget somewhere on your blog. I installed it at the bottom of this blog.
Use tag pre to publish your code. For example:
<pre name="code" class="SQL">
-- Sample
SELECT * FROM city;
</pre>
will produce this result
-- Sample
SELECT * FROM city;
Supported languages include c++, sql, c#, etc. All supported language tags can be found here.
