ReadPostgresData.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. //
  2. // ReadPostgresData.cs
  3. //
  4. // Uses the PostgresLibrary to retrieve a recordset.
  5. // This is not meant to be used in Production, but as a
  6. // learning aid in coding class System.Data.SqlClient.SqlDataReader.
  7. //
  8. // Bits of code were borrowed from libgda.
  9. //
  10. // Author:
  11. // Daniel Morgan <[email protected]>
  12. //
  13. // (C) 2002 Daniel Morgan
  14. //
  15. using System;
  16. using System.Data;
  17. using System.Runtime.InteropServices;
  18. using System.Diagnostics;
  19. namespace LearnToCreateSqlDataReader
  20. {
  21. sealed public class PostgresHelper {
  22. public static object OidTypeToSystem (int oid, string value) {
  23. object obj = null;
  24. Console.WriteLine("===== oid: " + oid + " value: " + value);
  25. switch(oid) {
  26. case 1043: // varchar
  27. Console.WriteLine("oid 1023 varchar ==> String found");
  28. obj = (object) String.Copy(value); // String
  29. break;
  30. case 25: // text
  31. Console.WriteLine("oid 25 text ==> String found");
  32. obj = (object) String.Copy(value); // String
  33. break;
  34. case 18: // char
  35. Console.WriteLine("oid 18 char ==> String found");
  36. obj = (object) String.Copy(value); // String
  37. break;
  38. case 16: // bool
  39. Console.WriteLine("oid 16 bool ==> Boolean found");
  40. obj = (object) Boolean.Parse(value);
  41. break;
  42. case 21: // int2
  43. Console.WriteLine("oid 21 int2 ==> Int16 found");
  44. obj = (object) Int16.Parse(value);
  45. break;
  46. case 23: // int4
  47. Console.WriteLine("oid 23 int4 ==> Int32 found");
  48. obj = (object) Int32.Parse(value);
  49. break;
  50. case 20: // int8
  51. Console.WriteLine("oid 20 int8 ==> Int64 found");
  52. obj = (object) Int64.Parse(value);
  53. break;
  54. default:
  55. Console.WriteLine("OidTypeToSystem Not Done Yet: oid: " +
  56. oid + " Value: " + value);
  57. break;
  58. }
  59. return obj;
  60. }
  61. public static Type OidToType (int oid) {
  62. Type typ = null;
  63. switch(oid) {
  64. case 1043: // varchar
  65. case 25: // text
  66. case 18: // char
  67. typ = typeof(String);
  68. break;
  69. case 16: // bool
  70. typ = typeof(Boolean);
  71. break;
  72. case 21: // int2
  73. typ = typeof(Int16);
  74. break;
  75. case 23: // int4
  76. typ = typeof(Int32);
  77. break;
  78. case 20: // int8
  79. typ = typeof(Int64);
  80. break;
  81. default:
  82. throw new NotImplementedException(
  83. "PGNI2: PostgreSQL oid type " + oid +
  84. " not mapped to .NET System Type.");
  85. }
  86. return typ;
  87. }
  88. }
  89. sealed public class PostgresLibrary {
  90. public enum ConnStatusType {
  91. CONNECTION_OK,
  92. CONNECTION_BAD,
  93. CONNECTION_STARTED,
  94. CONNECTION_MADE,
  95. CONNECTION_AWAITING_RESPONSE,
  96. CONNECTION_AUTH_OK,
  97. CONNECTION_SETENV
  98. }
  99. public enum PostgresPollingStatusType {
  100. PGRES_POLLING_FAILED = 0,
  101. PGRES_POLLING_READING,
  102. PGRES_POLLING_WRITING,
  103. PGRES_POLLING_OK,
  104. PGRES_POLLING_ACTIVE
  105. }
  106. public enum ExecStatusType {
  107. PGRES_EMPTY_QUERY = 0,
  108. PGRES_COMMAND_OK,
  109. PGRES_TUPLES_OK,
  110. PGRES_COPY_OUT,
  111. PGRES_COPY_IN,
  112. PGRES_BAD_RESPONSE,
  113. PGRES_NONFATAL_ERROR,
  114. PGRES_FATAL_ERROR
  115. }
  116. [DllImport("pq")]
  117. public static extern string PQerrorMessage (IntPtr conn);
  118. // char *PQerrorMessage(const PGconn *conn);
  119. [DllImport("pq")]
  120. public static extern IntPtr PQconnectdb(String conninfo);
  121. // PGconn *PQconnectdb(const char *conninfo)
  122. [DllImport("pq")]
  123. public static extern void PQfinish(IntPtr conn);
  124. // void PQfinish(PGconn *conn)
  125. [DllImport("pq")]
  126. public static extern IntPtr PQexec(IntPtr conn,
  127. String query);
  128. // PGresult *PQexec(PGconn *conn, const char *query);
  129. [DllImport("pq")]
  130. public static extern int PQntuples (IntPtr res);
  131. // int PQntuples(const PGresult *res);
  132. [DllImport("pq")]
  133. public static extern int PQnfields (IntPtr res);
  134. // int PQnfields(const PGresult *res);
  135. [DllImport("pq")]
  136. public static extern ConnStatusType PQstatus (IntPtr conn);
  137. // ConnStatusType PQstatus(const PGconn *conn);
  138. [DllImport("pq")]
  139. public static extern ExecStatusType PQresultStatus (IntPtr res);
  140. // ExecStatusType PQresultStatus(const PGresult *res);
  141. [DllImport("pq")]
  142. public static extern string PQresStatus (ExecStatusType status);
  143. // char *PQresStatus(ExecStatusType status);
  144. [DllImport("pq")]
  145. public static extern string PQresultErrorMessage (IntPtr res);
  146. // char *PQresultErrorMessage(const PGresult *res);
  147. [DllImport("pq")]
  148. public static extern int PQbinaryTuples (IntPtr res);
  149. // int PQbinaryTuples(const PGresult *res);
  150. [DllImport("pq")]
  151. public static extern string PQfname (IntPtr res,
  152. int field_num);
  153. // char *PQfname(const PGresult *res,
  154. // int field_num);
  155. [DllImport("pq")]
  156. public static extern int PQfnumber (IntPtr res,
  157. string field_name);
  158. // int PQfnumber(const PGresult *res,
  159. // const char *field_name);
  160. [DllImport("pq")]
  161. public static extern int PQfmod (IntPtr res, int field_num);
  162. // int PQfmod(const PGresult *res, int field_num);
  163. [DllImport("pq")]
  164. public static extern int PQftype (IntPtr res,
  165. int field_num);
  166. // Oid PQftype(const PGresult *res,
  167. // int field_num);
  168. [DllImport("pq")]
  169. public static extern int PQfsize (IntPtr res,
  170. int field_num);
  171. // int PQfsize(const PGresult *res,
  172. // int field_num);
  173. [DllImport("pq")]
  174. public static extern string PQcmdStatus (IntPtr res);
  175. // char *PQcmdStatus(PGresult *res);
  176. [DllImport("pq")]
  177. public static extern string PQoidStatus (IntPtr res);
  178. // char *PQoidStatus(const PGresult *res);
  179. [DllImport("pq")]
  180. public static extern int PQoidValue (IntPtr res);
  181. // Oid PQoidValue(const PGresult *res);
  182. [DllImport("pq")]
  183. public static extern string PQcmdTuples (IntPtr res);
  184. // char *PQcmdTuples(PGresult *res);
  185. [DllImport("pq")]
  186. public static extern string PQgetvalue (IntPtr res,
  187. int tup_num, int field_num);
  188. // char *PQgetvalue(const PGresult *res,
  189. // int tup_num, int field_num);
  190. [DllImport("pq")]
  191. public static extern int PQgetlength (IntPtr res,
  192. int tup_num, int field_num);
  193. // int PQgetlength(const PGresult *res,
  194. // int tup_num, int field_num);
  195. [DllImport("pq")]
  196. public static extern int PQgetisnull (IntPtr res,
  197. int tup_num, int field_num);
  198. // int PQgetisnull(const PGresult *res,
  199. // int tup_num, int field_num);
  200. [DllImport("pq")]
  201. public static extern void PQclear (IntPtr res);
  202. // void PQclear(PGresult *res);
  203. }
  204. public class ReadPostgresData
  205. {
  206. static void Test(String sConnInfo) {
  207. String errorMessage;
  208. IntPtr pgConn;
  209. PostgresLibrary.ConnStatusType connStatus;
  210. String sQuery;
  211. IntPtr pgResult;
  212. sQuery =
  213. "select tid, tdesc, aint4, abpchar " +
  214. "from sometable ";
  215. pgConn = PostgresLibrary.PQconnectdb (sConnInfo);
  216. connStatus = PostgresLibrary.PQstatus (pgConn);
  217. if(connStatus ==
  218. PostgresLibrary.
  219. ConnStatusType.CONNECTION_OK) {
  220. Console.WriteLine("CONNECTION_OK");
  221. Console.WriteLine("SQL: " + sQuery);
  222. pgResult = PostgresLibrary.PQexec(pgConn, sQuery);
  223. PostgresLibrary.ExecStatusType execStatus;
  224. execStatus = PostgresLibrary.
  225. PQresultStatus (pgResult);
  226. if(execStatus ==
  227. PostgresLibrary.
  228. ExecStatusType.PGRES_TUPLES_OK)
  229. {
  230. Console.WriteLine("PGRES_TUPLES_OK");
  231. int nRows = PostgresLibrary.
  232. PQntuples(pgResult);
  233. Console.WriteLine("Rows: " + nRows);
  234. int nFields = PostgresLibrary.
  235. PQnfields(pgResult);
  236. Console.WriteLine("Columns: " + nFields);
  237. String fieldName;
  238. // get meta data fromm result set (schema)
  239. // for each column (field)
  240. for(int fieldIndex = 0;
  241. fieldIndex < nFields;
  242. fieldIndex ++) {
  243. // get column name
  244. fieldName = PostgresLibrary.
  245. PQfname(pgResult, fieldIndex);
  246. Console.WriteLine("Field " +
  247. fieldIndex + ": " +
  248. fieldName);
  249. int oid;
  250. // get PostgreSQL data type (OID)
  251. oid = PostgresLibrary.
  252. PQftype(pgResult, fieldIndex);
  253. Console.WriteLine("Data Type oid: " + oid);
  254. int definedSize;
  255. // get defined size of column
  256. definedSize = PostgresLibrary.
  257. PQfsize(pgResult, fieldIndex);
  258. Console.WriteLine("definedSize: " +
  259. definedSize);
  260. }
  261. // for each row and column, get the data value
  262. for(int row = 0;
  263. row < nRows;
  264. row++) {
  265. for(int col = 0;
  266. col < nFields;
  267. col++) {
  268. String value;
  269. // get data value
  270. value = PostgresLibrary.
  271. PQgetvalue(
  272. pgResult,
  273. row, col);
  274. Console.WriteLine("Row: " + row +
  275. " Col: " + col);
  276. Console.WriteLine("Value: " +
  277. value);
  278. int columnIsNull;
  279. // is column NULL?
  280. columnIsNull = PostgresLibrary.
  281. PQgetisnull(pgResult,
  282. row, col);
  283. Console.WriteLine("Data is " +
  284. (columnIsNull == 0 ? "NOT NULL" : "NULL"));
  285. int actualLength;
  286. // get Actual Length
  287. actualLength = PostgresLibrary.
  288. PQgetlength(pgResult,
  289. row, col);
  290. Console.WriteLine("Actual Length: " +
  291. actualLength);
  292. }
  293. }
  294. // close result set
  295. PostgresLibrary.PQclear (pgResult);
  296. }
  297. else {
  298. // display execution error
  299. errorMessage = PostgresLibrary.
  300. PQresStatus(execStatus);
  301. errorMessage += " " + PostgresLibrary.
  302. PQresultErrorMessage(pgResult);
  303. Console.WriteLine(errorMessage);
  304. }
  305. // close database conneciton
  306. PostgresLibrary.PQfinish(pgConn);
  307. }
  308. else {
  309. errorMessage = PostgresLibrary.
  310. PQerrorMessage (pgConn);
  311. errorMessage += ": Could not connect to database.";
  312. Console.WriteLine(errorMessage);
  313. }
  314. }
  315. public static object ExecuteScalar(string sConnInfo, string sQuery) {
  316. object obj = null; // return
  317. int nRow;
  318. int nCol;
  319. String errorMessage;
  320. IntPtr pgConn;
  321. PostgresLibrary.ConnStatusType connStatus;
  322. IntPtr pgResult;
  323. pgConn = PostgresLibrary.PQconnectdb (sConnInfo);
  324. connStatus = PostgresLibrary.PQstatus (pgConn);
  325. if(connStatus ==
  326. PostgresLibrary.
  327. ConnStatusType.CONNECTION_OK) {
  328. Console.WriteLine("CONNECTION_OK");
  329. pgResult = PostgresLibrary.PQexec(pgConn, sQuery);
  330. PostgresLibrary.ExecStatusType execStatus;
  331. execStatus = PostgresLibrary.
  332. PQresultStatus (pgResult);
  333. if(execStatus ==
  334. PostgresLibrary.
  335. ExecStatusType.PGRES_TUPLES_OK) {
  336. Console.WriteLine("PGRES_TUPLES_OK");
  337. int nRows = PostgresLibrary.
  338. PQntuples(pgResult);
  339. Console.WriteLine("Rows: " + nRows);
  340. int nFields = PostgresLibrary.
  341. PQnfields(pgResult);
  342. Console.WriteLine("Columns: " + nFields);
  343. if(nRows > 0 && nFields > 0) {
  344. nRow = 0;
  345. nCol = 0;
  346. // get column name
  347. String fieldName;
  348. fieldName = PostgresLibrary.
  349. PQfname(pgResult, nCol);
  350. Console.WriteLine("Field " +
  351. nCol + ": " +
  352. fieldName);
  353. int oid;
  354. // get PostgreSQL data type (OID)
  355. oid = PostgresLibrary.
  356. PQftype(pgResult, nCol);
  357. Console.WriteLine("Data Type oid: " + oid);
  358. int definedSize;
  359. // get defined size of column
  360. definedSize = PostgresLibrary.
  361. PQfsize(pgResult, nCol);
  362. Console.WriteLine("DefinedSize: " +
  363. definedSize);
  364. String value;
  365. // get data value
  366. value = PostgresLibrary.
  367. PQgetvalue(
  368. pgResult,
  369. nRow, nCol);
  370. Console.WriteLine("Row: " + nRow +
  371. " Col: " + nCol);
  372. Console.WriteLine("Value: " + value);
  373. int columnIsNull;
  374. // is column NULL?
  375. columnIsNull = PostgresLibrary.
  376. PQgetisnull(pgResult,
  377. nRow, nCol);
  378. // isNull = *thevalue != '\0' ? FALSE : PQgetisnull (pg_res, rownum, i);
  379. Console.WriteLine("Data is " +
  380. (columnIsNull == 0 ? "NOT NULL" : "NULL"));
  381. int actualLength;
  382. // get Actual Length
  383. actualLength = PostgresLibrary.
  384. PQgetlength(pgResult,
  385. nRow, nCol);
  386. Console.WriteLine("Actual Length: " +
  387. actualLength);
  388. obj = PostgresHelper.
  389. OidTypeToSystem (oid, value);
  390. }
  391. // close result set
  392. PostgresLibrary.PQclear (pgResult);
  393. }
  394. else {
  395. // display execution error
  396. errorMessage = PostgresLibrary.
  397. PQresStatus(execStatus);
  398. errorMessage += " " + PostgresLibrary.
  399. PQresultErrorMessage(pgResult);
  400. Console.WriteLine(errorMessage);
  401. }
  402. // close database conneciton
  403. PostgresLibrary.PQfinish(pgConn);
  404. }
  405. else {
  406. errorMessage = PostgresLibrary.
  407. PQerrorMessage (pgConn);
  408. errorMessage += ": Could not connect to database.";
  409. Console.WriteLine(errorMessage);
  410. }
  411. return obj;
  412. }
  413. static void TestExecuteScalar(String connString) {
  414. String selectStatement;
  415. try {
  416. selectStatement =
  417. "select count(*) " +
  418. "from sometable";
  419. Int64 myCount = (Int64) ExecuteScalar(connString,
  420. selectStatement);
  421. Console.WriteLine("Count: " + myCount);
  422. selectStatement =
  423. "select max(tdesc) " +
  424. "from sometable";
  425. string myMax = (string) ExecuteScalar(connString,
  426. selectStatement);
  427. Console.WriteLine("Max: " + myMax);
  428. }
  429. catch(Exception e) {
  430. Console.WriteLine(e);
  431. }
  432. }
  433. [STAThread]
  434. static void Main(string[] args)
  435. {
  436. // PostgreSQL DBMS Connection String
  437. // Notice how the parameters are separated with spaces
  438. // An OLE-DB Connection String uses semicolons to
  439. // separate parameters.
  440. String sConnInfo =
  441. "host=localhost " +
  442. "dbname=test " +
  443. "user=postgres";
  444. Test(sConnInfo);
  445. TestExecuteScalar(sConnInfo);
  446. Type t;
  447. int oid;
  448. oid = 1043;
  449. t = PostgresHelper.OidToType(oid); // varchar ==> String
  450. Console.WriteLine("OidToType varchar oid: " + oid +
  451. " ==> t: " + t.ToString());
  452. oid = 23;
  453. t = PostgresHelper.OidToType(oid); // int4 ==> Int32
  454. Console.WriteLine("OidToType int4 oid: " + oid +
  455. " ==> t: " + t.ToString());
  456. }
  457. }
  458. }