# Wednesday, September 14, 2005

Yag's blog entry on LINQ
I was reading some blogs earlier today and I saw that Yag had posted an entry out on the VS Data Teams Weblog entitled "Project LINQ - Language INtegrated Query (by yag)". Interesting stuff coming out of the PDC for sure. He shows a query that is essentially dimensioning a Visual Basic variable as a collection using a SQL statement.

I haven't seen LINQ yet or been able to play around with it, but I think I get the gist of it pretty well from yag's description. So, that got me to thinking how hard would something like that be to do in Visual FoxPro? There are some interesting aspects to what yag's example...

Dim SmallCountries = Select Country _
From Country In Countries _
Where Country.Population < 1000000

...and his description of LINQ show. Being able to use SQL to access objects, data, and XML (still just data) and return collections of objects or perhaps other constructs is interesting to me anyways. But implementing something similar in Visual FoxPro doesn't strike me as terribly difficult (here again, bear in mind that I have not seen LINQ and I could be talking out of my proverbial back-side right now... I'll know more when I get my hands on it), in fact, given Visual FoxPro's ability to manipulate data, XML, and objects, it is a perfect fit for this sort of extension. I don't wish to take anything away from the hard work that MS did to come up with LINQ. I merely wish to take that idea and run with it for a little bit in Visual FoxPro. Can you blame me?

A few disclaimers
Now the SQL Parsing engine they are using in LINQ is surely heads and shoulders above what I'm about to show you, please remember that I've spent a total of about 1 hour on this and part of that time was spent getting a list of countries and stats for the example. I just wanted to show a proof-of-concept for now. I'll let it roll around in my head for a few days, and also look for feedback from the VFP Community, before I decide whether I want to get down to some serious code writing with this thing or not. And, this example only shows running queries against a collection. Data and XML will come later, but I don't perceive any real stumbling blocks there either... some tedious work perhaps, but no show-stoppers.

VOSQL, a proof-of-concept
I call this thing "Visual FoxPro Object-Oriented SQL (VOSQL)". Copy-n-paste the code below into a PRG and execute it from within VFP. There's a lot of code, but most of it is just creating the extensive cursor of countries that I use to populate the countries collection. If you look, the VOSQL class is rather short (almost laughable for the amount of functionality it already gives). I've made this example a little more difficult then Yag's, by adding an additional World collection to hold the countries and showing some more complex SQL statements (I couldn't let the .NET family have all the fun). Here's the code (be sure and try some of your own SQL statements as well)...

*!* Cut-N-Paste the following code into a PRG and execute it
PRIVATE oWorld AS world
LOCAL loVOSQL AS VOSQL, loCountry as country

DO CreateCountryCursor && This is just to give us some sample data from which to pull our countries

*!* Fill the World Collection
oWorld = CREATEOBJECT("world")
SELECT crsCountry
SCAN ALL
 oWorld.countries.ADD(CREATEOBJECT("Country", ALLTRIM(crsCountry.country),  ALLTRIM(crsCountry.capital), crsCountry.area, crsCountry.population))
ENDSCAN

USE IN SELECT("crsCountry") && close it now that we're done

************************************
*!* Example Queries using the VOSQL object
************************************
loVOSQL = CREATEOBJECT("VOSQL")

*!* Query #1
colCountries = loVOSQL.ObjectQuery("SELECT Country FROM oWorld.Countries WHERE Population < 1000000")
FOR EACH loCountry IN colCountries
 ?loCountry.cName + [ - ] + TRANSFORM(loCountry.population)
ENDFOR
?

*!* Query #2
colCountries = loVOSQL.ObjectQuery("Select Country from oWorld.Countries Where 2500000 < Area AND (Population > 20000000 or alltrim(cName) = [Kazakhstan])")
FOR EACH loCountry IN colCountries
 ?loCountry.cName
ENDFOR
?

*!* Query #3
colCountries = loVOSQL.ObjectQuery("SELECT Country FROM oWorld.Countries WHERE 2500000 < Area AND (Population > 20000000 or alltrim(cName) = [Kazakhstan])  ORDER BY Capital")
FOR EACH loCountry IN colCountries
 ?loCountry.cName
ENDFOR
?

************************************
*!* Classes we are querying against
************************************
DEFINE CLASS country AS CUSTOM
 cName = "Unknown"
 capital = "Unknown"
 area = 0
 population = 0
 PROCEDURE INIT (tcName, tcCapital, tnArea, tnPopulation)
  WITH THIS
   .cName = tcName
   .capital = tcCapital
   .area = tnArea
   .population = tnPopulation
  ENDWITH
 ENDPROC
ENDDEFINE

DEFINE CLASS world AS CUSTOM
 Name = "Earth"
 ADD OBJECT countries AS countries
ENDDEFINE

DEFINE CLASS countries AS COLLECTION
ENDDEFINE

************************************
*!* This is the actual object that does the work
************************************
DEFINE CLASS VOSQL AS CUSTOM
 PROCEDURE ObjectQuery (tcOSQL)
  LOCAL lcSelect, lcFrom, loFrom, lcWhere, lcOrderBy, lnDescending, lnAscending, loReturn, loItem, lcReturnName, ;
   lnCounter, lnPropCount, llWhereProcessed
  lcFrom = STREXTRACT(tcOSQL, " FROM " , " WHERE ", 1, 3)
  loReturn = CREATEOBJECT("Collection")
  loFrom = &lcFrom
  IF loFrom.COUNT > 1
   llWhereProcessed = .F.
   lcSelect = UPPER(STREXTRACT(tcOSQL, "SELECT " , " FROM ", 1, 1))
   lcWhere = " " + STREXTRACT(tcOSQL, " WHERE " , " ORDER BY ", 1, 3)
   lcOrderBy = STREXTRACT(tcOSQL, " ORDER BY " , "", 1, 3)
   lnDescending = ATC(" DESC", lcOrderBy)
   IF lnDescending > 0
    lcOrderBy = LEFT(lcOrderBy, lnDescending - 1)
   ENDIF
   lnAscending = ATC(" ASC", lcOrderBy)
   IF lnAscending > 0
    lcOrderBy = LEFT(lcOrderBy, lnAscending - 1)
   ENDIF
   
   FOR lnCounter = 1 TO loFrom.COUNT
    loItem = loFrom.ITEM(lnCounter)
    IF UPPER(loItem.CLASS) == lcSelect
     IF !llWhereProcessed
      THIS.processwhereclause(@lcWhere, loItem)
      llWhereProcessed = .T.
     ENDIF
     IF EMPTY(lcWhere) OR EVALUATE(lcWhere)
      IF EMPTY(lcOrderby)
       loReturn.ADD(loItem)
      ELSE
       loReturn.ADD(loItem, TRANSFORM(EVALUATE("loItem." + lcOrderby)))
      ENDIF
     ENDIF
    ENDIF
   ENDFOR
  ENDIF
  IF !EMPTY(lcOrderby)
   IF lnDescending > 0
    loReturn.Keysort = 3
   ELSE
    loReturn.Keysort = 2
   ENDIF
  ENDIF
  RETURN loReturn
 ENDPROC

 PROCEDURE processwhereclause (tcWhere, toItem)
  LOCAL lnCounter, lnMax
  lnMax = AMEMBERS(aryProps, toItem, 0)
  FOR lnCounter = 1 TO lnMax
   tcWhere = STRTRAN(tcWhere, " " + ALLTRIM(aryProps(lnCounter)), " loItem." + aryProps(lnCounter), 1, -1, 1)
   tcWhere = STRTRAN(tcWhere, "(" + ALLTRIM(aryProps(lnCounter)), "(loItem." + aryProps(lnCounter), 1, -1, 1)
  ENDFOR
 ENDPROC
ENDDEFINE

************************************
*!* This is just to produce data for this sample
************************************
PROCEDURE CreateCountryCursor
 CREATE CURSOR crsCountry(country c(21), capital c(19), area I, population I)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Afghanistan", "Kabul", 647500, 29928987)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Albania", "Tirane", 28748, 3563112)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Algeria", "Algiers", 2381740, 32531853)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Andorra", "Andorra la Vella", 468, 70549)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Angola", "Luanda", 1246700, 11190786)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Antigua and Bar", "St. John's", 443, 68722)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Argentina", "Buenos Aires", 2766890, 39537943)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Armenia", "Yerevan", 29800, 2982904)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Australia", "Canberra", 7686850, 20090437)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Austria", "Vienna", 83858, 8184691)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Azerbaijan", "Baku", 86600, 7911974)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Bahamas, The", "Nassau", 13940, 301790)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Bahrain", "Al-Manamah", 665, 688345)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Bangladesh", "Dhaka", 144000, 144319628)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Barbados", "Bridgetown", 431, 279254)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Belarus", "Mensk (Minsk)", 207600, 10300483)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Belgium", "Brussels", 30510, 10364388)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Belize", "Belmopan", 22966, 279457)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Benin", "Porto-Novo", 112620, 7460025)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Bhutan", "Thimphu", 47000, 2232291)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Bolivia", "La Paz", 1098580, 8857870)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Bosnia and Herz", "Sarajevo", 51129, 4025476)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Botswana", "Gaborone", 600370, 1640115)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Brazil", "Bras¡lia", 8511965, 186112794)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Brunei", "Bandar Seri Begawan", 5770, 372361)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Bulgaria", "Sofia", 110910, 7450349)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Burkina Faso", "Ouagadougou", 274200, 13925313)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Burundi", "Bujumbura", 27830, 6370609)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Cambodia", "Phnom Penh", 181040, 13607069)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Cameroon", "Yaounde", 475440, 16380005)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Canada", "Ottawa", 9984670, 32805041)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Cape Verde", "Praia", 4033, 418224)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Central African", "Bangui", 622984, 3799897)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Chad", "N'Djamena", 1284000, 9826419)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Chile", "Santiago", 756950, 15980912)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("China", "Beijing", 9596960, 1306313812)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Colombia", "Bogat ", 1138910, 42954279)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Comoros", "Moroni", 2170, 671247)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Congo, Republic", "Brazzaville", 342000, 3039126)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Congo, Democrat", "Kinshasa", 2345410, 60085004)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Costa Rica", "San Jose", 51100, 4016173)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Cote d'Ivoire", "Yamoussoukro", 322460, 17298040)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Croatia", "Zagreb", 56542, 4495904)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Cuba", "Havana", 110860, 11346670)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Cyprus", "Nicosia", 9250, 780133)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Czech Republic", "Prague", 78866, 10241138)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Denmark", "Copenhagen", 43094, 5432335)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Djibouti", "Djibouti", 23000, 476703)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Dominica", "Roseau", 754, 69029)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Dominican Repub", "Santo Domingo", 48730, 8950034)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("East Timor", "Dili", 15007, 1040880)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Ecuador", "Quito", 283560, 13363593)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Egypt", "Cairo", 1001450, 77505756)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("El Salvador", "San Salvador", 21040, 6704932)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Equatorial Guin", "Malabo", 28051, 535881)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Eritrea", "Asmara", 121320, 4561599)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Estonia", "Tallinn", 45226, 1332893)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Ethiopia", "Addis Ababa", 1127127, 73053286)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Fiji", "Suva", 18270, 893354)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Finland", "Helsinki", 337030, 5223442)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("France", "Paris", 547030, 60656178)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Gabon", "Libreville", 267667, 1389201)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Gambia, The", "Banjul", 11300, 1593256)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Georgia", "Tbilisi", 69700, 4677401)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Germany", "Berlin", 357021, 82431390)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Ghana", "Accra", 239460, 21029853)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Greece", "Athens", 131940, 10668354)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Grenada", "St. George's", 344, 89502)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Guatemala", "Guatemala City", 108890, 14655189)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Guinea", "Conakry", 245857, 9467866)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Guinea-Bissau", "Bissau", 36120, 1416027)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Guyana", "Georgetown", 214970, 765283)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Haiti", "Port-au-Prince", 27750, 8121622)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Honduras", "Tegucigalpa", 112090, 6975204)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Hungary", "Budapest", 93030, 10006835)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Iceland", "Reykjavik", 103000, 296737)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("India", "New Delhi", 3287590, 1080264388)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Indonesia", "Jakarta", 1919440, 241973879)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Iran", "Tehran", 1648000, 68017860)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Iraq", "Baghdad", 437072, 26074906)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Ireland", "Dublin", 70280, 4015676)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Israel", "Jerusalem", 20770, 6276883)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Italy", "Rome", 301230, 58103033)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Jamaica", "Kingston", 10991, 2731832)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Japan", "Tokyo", 377835, 127417244)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Jordan", "Amman", 92300, 5759732)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Kazakhstan", "Almaty", 2717300, 15185844)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Kenya", "Nairobi", 582650, 33829590)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Kiribati", "Tarawa", 811, 103092)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Korea, North", "Pyongyang", 120540, 22912177)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Korea, South", "Seoul", 98480, 48422644)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Kuwait", "Kuwait City", 17820, 2335648)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Kyrgyzstan", "Bishkek", 198500, 5146281)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Laos", "Vientiane", 236800, 6217141)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Latvia", "Riga", 64589, 2290237)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Lebanon", "Beirut", 10400, 3826018)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Lesotho", "Maseru", 30355, 1867035)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Liberia", "Monrovia", 111370, 3482211)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Libya", "Tripoli", 1759540, 5765563)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Liechtenstein", "Vaduz", 160, 33717)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Lithuania", "Vilnius", 65200, 3596617)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Luxembourg", "Luxembourg", 2586, 468571)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Macedonia", "Skopje", 25333, 2045262)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Madagascar", "Antananarivo", 587040, 18040341)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Malawi", "Lilongwe", 118480, 12158924)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Malaysia", "Kuala Lumpur", 329750, 23953136)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Maldives", "Male", 300, 349106)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Mali", "Bamako", 1240000, 12291529)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Malta", "Valletta", 316, 398534)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Marshall Island", "Majuro", 181, 59071)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Mauritania", "Nouakchott", 1030700, 3086859)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Mauritius", "Port Louis", 2040, 1230602)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Mexico", "Mexico City", 1972550, 106202903)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Micronesia, Fed", "Palikir", 702, 108105)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Moldova", "Chisinau", 33843, 4455421)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Monaco", "Monaco", 2, 32409)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Mongolia", "Ulan Bator", 1565000, 2791272)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Morocco", "Rabat", 446550, 32725847)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Mozambique", "Maputo", 801590, 19406703)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Myanmar (Burma)", "Rangoon", 678500, 42909464)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Namibia", "Windhoek", 825418, 2030692)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Nauru", "Yaren", 21, 13048)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Nepal", "Kathmandu", 140800, 27676547)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Netherlands", "Amsterdam", 41526, 16407491)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("New Zealand", "Wellington", 268680, 4035461)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Nicaragua", "Managua", 129494, 5465100)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Niger", "Niamey", 1267000, 11665937)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Nigeria", "Abuja", 923768, 128771988)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Norway", "Oslo", 324220, 4593041)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Oman", "Muscat", 212460, 3001583)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Pakistan", "Islamabad", 803940, 162419946)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Palau", "Koror", 458, 20303)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Panama", "Panama City", 78200, 3039150)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Papua New Guine", "Port Moresby", 462840, 5545268)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Paraguay", "Asuncion", 406750, 6347884)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Peru", "Lima", 1285220, 27925628)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Philippines", "Manila", 300000, 87857473)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Poland", "Warsaw", 312685, 38635144)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Portugal", "Lisbon", 92391, 10566212)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Qatar", "Doha", 11437, 863051)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Romania", "Bucharest", 237500, 22329977)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Russia", "Moscow", 17075200, 143420309)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Rwanda", "Kigali", 26338, 8440820)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("St. Kitts and N", "Basseterre", 261, 38958)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("St. Lucia", "Castries", 616, 166312)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("St. Vincent and", "Kingstown", 389, 117534)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Samoa", "Apia", 2944, 177287)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("San Marino", "San Marino", 61, 28880)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Sao Tome and Principe", "Sao Tome", 1001, 187410)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Saudi Arabia", "Riyadh", 1960582, 26417599)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Senegal", "Dakar", 196190, 11126832)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Serbia and Mont", "Belgrade", 102350, 10829175)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Seychelles", "Victoria", 455, 81188)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Sierra Leone", "Freetown", 71740, 6017643)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Singapore", "Singapore", 693, 4425720)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Slovakia", "Bratislava", 48845, 5431363)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Slovenia", "Ljubljana", 20273, 2011070)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Solomon Islands", "Honiara", 28450, 538032)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Somalia", "Mogadishu", 637657, 8591629)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("South Africa", "Pretoria", 1219912, 44344136)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Spain", "Madrid", 504782, 40341462)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Sri Lanka", "Colombo", 65610, 20064776)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Sudan", "Khartoum", 2505810, 40187486)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Suriname", "Paramaribo", 163270, 438144)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Swaziland", "Mbabane", 17363, 1173900)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Sweden", "Stockholm", 449964, 9001774)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Switzerland", "Bern", 41290, 7489370)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Syria", "Damascus", 185180, 18448752)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Taiwan", "Taipei", 35980, 22894384)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Tajikistan", "Dushanbe", 143100, 7163506)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Tanzania", "Dar es Salaam", 945087, 36766356)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Thailand", "Bangkok", 514000, 65444371)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Togo", "Lome", 56785, 5681519)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Tonga", "Nuku'alofa", 748, 112422)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Trinidad and To", "Port-of-Spain", 5128, 1088644)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Tunisia", "Tunis", 163610, 10074951)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Turkey", "Ankara", 780580, 69660559)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Turkmenistan", "Ashgabat", 488100, 4952081)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Tuvalu", "Funafuti", 26, 11636)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Uganda", "Kampala", 236040, 27269482)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Ukraine", "Kyiv (Kiev)", 603700, 47425336)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("United Arab Emi", "Abu Dhabi", 82880, 2563212)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("United Kingdom", "London", 244820, 60441457)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("United States", "Washington, D.C.", 9629091, 295734134)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Uruguay", "Montevideo", 176220, 3415920)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Uzbekistan", "Tashkent", 447400, 26851195)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Vanuatu", "Vila", 12200, 205754)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Vatican City", "", 0, 921)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Venezuela", "Caracas", 912050, 25375281)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Vietnam", "Hanoi", 329560, 83535576)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Western Sahara", "", 266000, 273008)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Yemen", "Sana ", 527970, 20727063)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Zambia", "Lusaka", 752614, 11261795)
 INSERT INTO crsCountry(country, capital, area, population) VALUES ("Zimbabwe", "Harare", 390580, 12746990)
ENDPROC

Wednesday, September 14, 2005 8:30:42 AM (GMT Daylight Time, UTC+01:00)  #    Comments [9]
Wednesday, September 14, 2005 6:30:50 PM (GMT Daylight Time, UTC+01:00)
What's your next challenge? figuring out how to get VFP to read C# and VB.Net?
Wednesday, September 14, 2005 7:19:20 PM (GMT Daylight Time, UTC+01:00)
Hi Andrew,

Well, if we really wanted to get crazy, we could always try to create a compiler that would convert VFP source into MSIL. Imagine... the VFP Community porting Visual FoxPro to .NET themselves, creating a hybrid that could create standard VFP applications or .NET applications. I've often wondered how hard it would be... seems like it is feasibly possible, especially given the ability we have to extend the VFP IDE. However, whether this drastic step would even be necessary depends on what Sedna will offer. I'm of the mind that Sedna will be a lot more than most VFP developers currently think.
Thursday, September 15, 2005 4:53:40 AM (GMT Daylight Time, UTC+01:00)
Craig and Andrew,

I've posted and begged for a Sedna enhancement that would provide a hook that would allow a developer to pre-process VFP source code before the VFP compiler sees it. This would provide a way for the community to enhance the VFP language (VFP++) without changing the compiler engine similar to the way that C++ was originally built on top of the standard C compiler.

I know that we could build a project hook to pre-process code during a BUILD cycle, but this would only allow us to pre-process PRG based code. VFP automatically compiles code entered in any of its designers (form, class, report/label).

By hooking the generic compilation engine, a pre-processor could parse and prep source from not only PRG files, but all designers, the command window, and even at runtime when the COMPILE or EXECSCRIPT commands are invoked.

If I had a single wish for Sedna, this would be it.

Malcolm

Tuesday, September 27, 2005 10:27:33 AM (GMT Daylight Time, UTC+01:00)
Hi Craig,
can´t believe how dynamic (Sedna, LINQ) this whole thing has gotten lately (again).

As for your sample: If you checked out LINQ in the meantime you will have noticed that you underestimated the depth of it.

Not knowing it you missed core features:
Enabling Intellisense by freeing the query from its string (de)limiters and making it native to the language. What arguments get passed to the SQL server behind the scenes is black-boxed by DLINQ.

Guess most of the functionality can / could be retrofitted to VFP, but the question is: What do we gain and is it worth the time and effort.

It´s VERY elegant what Anders Hejlsberg showed at PDC and it´s great they finally take .Net next year (or 2007) where VFP´s been for a decade (but even further).

It´s very elegant to query an array or a collection or just anything, but I can iterate over it very easily too and sort / order it.

Sadly this will actually be the point where we can let VFP slowly retire and leave Ken alone with begging for version X, as VB + .Net will finally be up to and above VFP.

In the Sedna category on UT I asked for making the [] delimiters 'transparent' for Intellisense and syntax checking - as they already are for the pre-processor, finding and replacing #defines, even when in strings - when delimited with []. - Poor VFPer´s LINQ and a possible quick and dirty Sedna fix.

Interesting times
Cheers
G
Wednesday, September 28, 2005 2:37:21 AM (GMT Daylight Time, UTC+01:00)
The preceding comment is almost verbatim from one on another BBS...

It also completely ignores several issues. Simplification and "black boxing" is grand, but lets not pretend that data access will become a standardized task with all complexity hidden away. We've all seen (and abandoned) "Application Generator" Wizards that made the same claims. Good developers will keep consider data access *in terms of the underlying data* to make decisions about SQL, T-SQL, X-Query etc. They won't rely on any "black box", they'll customize to best effect. There is nothing new about this.

If you truly consider LINQ's goals, there is nothing incompatible or improper about a VFP "Project LINQ".
Joseph Kerr
Wednesday, September 28, 2005 5:26:09 PM (GMT Daylight Time, UTC+01:00)
>If you truly consider LINQ's goals, there is nothing incompatible or improper about a VFP "Project LINQ".

Joseph,
I was just trying to put in relation what I saw here and from Greg Reichert on UT# 1053144 AND what I saw from Anders Hejlsberg in the PDC keynote, his whitepapers, the VB team on Channel9 and DotNetRocks,...

What I see here and on UT doesn´t compare to the breadth, width and depth of LINQ at all.

I share the enthusiasm for LINQ and for VFP and I have no intention whatsoever to quarrel with gurus like Craig Boyd,... It´s just my personal comparison POV.

No offense intended
G
Saturday, October 01, 2005 5:57:44 AM (GMT Daylight Time, UTC+01:00)
I'll be back to this subject once I have had the opportunity to study LINQ in more detail. I realize that I haven't reproduced anything remotely close to the overall breadth adn depth of LINQ (I spent a total of 1 hour on this so far), but I hope to perhaps explore this further as time allows. Right now I am getting ready for Southwest Fox, so with my billable work and that I am pretty tied up at the moment.

Is it worth the effort? Perhaps. I will know more once I have had the opportunity to educate myself and can reach an informed opinion. There are many factors to consider... Would the feature add significant ability that VFP developers would find useful? Would the additional exposure for VFP be worth the effort? Would it perhaps help stymie some of the feelings that VFP is less than (an ignorant feeling, but one that never-the-less exists)? These and more should probably be taken into consideration.

I wish I had the time to explore and answer these questions for myself, but time is short these days. So, it will maybe have to wait until after Southwest Fox. And, I am hoping to see many of you there.
Monday, October 03, 2005 4:29:52 PM (GMT Daylight Time, UTC+01:00)
Craig, Joseph, Greg,...
it´s comforting to see that everybody has calmed down again and check where their shots from the waist have ended up.

I´m really not comfortable in the role of the 'consultant' 'who knows better', but isn´t able to code something remotely complex himself, so I´m relying on you to come up with some implementation.

With some time at hand I´ve been trying to come up with some ideas for some Sedna doable 'real fake LINQ' (the Intellisense 'transparent' delimiters), 'fake LINQ' - possibly .Net LINQ in VFP My (???) or some 'real Fox LINQ' by extending the ancient 'FINQ' SELECT .. FROM clause with Connection!Table and Objects.

As the latter one doesn´t seem feasible, very probably requiring some major tinkering in the VFP core, maybe we could turn the syntax around like in C# and do a 'little' FROM class with methods like WHERE, ORDERBY and SELECT, spitting out a SQL string and working against collections too.

Ok, these were some more wise-a** ideas. Now come and implement, code-slaves! >fg<
And KISS!
And take it lightly - the way it is meant! - Some discussion stuff for Southwest. Maybe this will even get me out of my hole for the Frankfurt weekend.
Cheers
G
Wednesday, October 05, 2005 10:28:21 PM (GMT Daylight Time, UTC+01:00)
Seems that I somehow felt that I dealt with a real guru.
*************************************
Congrats to your new MVP title!!!!!!!
*************************************
What do you think, could an MVP get

WITH Connection
*Tell VFP that SQL CMDs bracketed here go to a server
*Instead of
*SQLEXEC(Connection,'USE pubs')
*SQLEXEC(Connection,'SELECT * FROM authors')
USE pubs
SELECT * FROM authors
*but send it off as SQLEXEC statements as above?!
*Any idea how to fit in the 3rd and 4th argument to SQLEXEC?
ENDWITH

Congrats again
G
All comments require the approval of the site owner before being displayed.
Name
E-mail
(will show your gravatar icon)
Home page

Comment (Some html is allowed: a@href@title, b, blockquote@cite, em, i, strike, strong, sub, sup, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview

 

Archive

<March 2010>
SunMonTueWedThuFriSat
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910