1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671
|
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
-
- This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
- project.
-
- Copyright (C) 1998-2018 OpenLink Software
-
- This project is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; only version 2 of the License, dated June 1991.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-
-->
<sect1 id="odbcimplementation"><title>Virtuoso Driver for ODBC</title>
<sect2 id="virtdsnsetup"><title>Windows ODBC Driver Configuration</title>
<para>At installation time two ODBC data source names (DSN's)
are created with default values by the Virtuoso installer, the first DSN named "Local
Virtuoso" provides a link to a local default Virtuoso database server instance, while
the other named "Local Virtuoso Demo" provides a link to a local Virtuoso server
for the Virtuoso demonstration database.</para>
<para>The process of creating additional ODBC DSN's for you Virtuoso drivers for ODBC
is explained in the steps that follow:</para>
<orderedlist>
<listitem><para>Go to the Windows <emphasis>Control panel</emphasis>.</para></listitem>
<listitem><para>Double click on the <emphasis>ODBC Administrator</emphasis> applet.
On Windows 2000 / XP the ODBC Administrator applet may be called
<emphasis>Data Source (ODBC)</emphasis> and may be found under Administrative
tools icon of the Control Panel.</para></listitem>
<listitem><para>Once the ODBC Administrator has been loaded choose by selecting
the appropriate panel whether you want a new User or System Data Source. User
Data Sources will only be available to the user that created them. System Data
Sources will be available to all users and applications on the system.</para></listitem>
<listitem><para>Click on the <emphasis>Add</emphasis> Data Source Name button</para></listitem>
<listitem><para>Select the Driver named <emphasis>OpenLink Virtuoso Driver</emphasis></para></listitem>
<listitem><para>Enter values into the fields presented by the Virtuoso
Driver's DSN configuration dialog:</para>
<figure id="virtdsn001" float="1"><title>Virtuoso ODBC Driver Setup Dialogue for Windows</title>
<graphic fileref="virtdsn001.png"/></figure>
<para><emphasis>Name:</emphasis> provide a name that will act as a logical
reference to the Virtuoso database server that you will be connecting to.
Subsequent references to this database will be made to this value when ODBC
compliant applications interact with your Virtuoso driver.</para>
<para><emphasis>Description:</emphasis> allows you to provide a short
description about the nature of the connection. This is optional.</para>
<para><emphasis>Server:</emphasis> enter the hostname or IP address of the
machine hosting your Virtuoso server and enter the port number that Virtuoso is
listening at. This is configured in the <link linkend="VIRTINI">Virtuoso ini</link>
file on the server.</para></listitem>
<listitem><para>Press the <emphasis>Next</emphasis> button to configure more
details about the connection</para>
<figure id="virtdsn002" float="1"><title>Virtuoso ODBC Driver Setup Dialogue for Windows</title>
<graphic fileref="virtdsn002.ong"/></figure>
<para><emphasis>Connect to the Virtuoso Servet to obtain default settings for the
additional configuration options:</emphasis> allows you to specify the default username
and password for the connection.</para>
<para>Press the <emphasis>Next</emphasis> button</para>
<para><emphasis>Database:</emphasis> allows you to select the default database
for the connection. You will need to check the box above and supply a password
to refresh this list. Objects created or selected without an explicit
catalogue/database qualifier will automatically be sought from this select database.</para>
<para><emphasis>Charset:</emphasis> lets you choose the default character set
for the connection.</para>
<!-- <para><emphasis>Test database connection</emphasis> can be used to
test your configuration</para>
<para>supply the remaining details (usually only password) and press ok to test.
If all is well then you will have returned the confirmation box</para>
-->
<figure id="virtdsn003" float="1"><title>Virtuoso ODBC Driver Setup Dialogue for Windows</title>
<graphic fileref="virtdsn003.png" width="354px" depth="287px"/></figure>
<!--
<figure id="virtdsn004" float="1"><title>Virtuoso ODBC Driver Setup Dialogue for Windows</title>
<graphic fileref="virtdsn004.jpg" width="380px" depth="126px"/></figure>
-->
</listitem>
<!--
<listitem><para>Press <emphasis>Next</emphasis> to configure encryption</para>
<figure id="virtdsn005" float="1"><title>Virtuoso ODBC Driver Setup Dialogue for Windows</title>
<graphic fileref="virtdsn005.jpg" width="420px" depth="333px"/></figure>
<para>The <emphasis>Encrypted</emphasis> checkbox specifies an encrypted
connection when checked.</para>
<para>A <emphasis>PKCS#12 file</emphasis> certificate must be supplied
for the server to authorize the connection.
See <link linkend="x509odbcclient">Using SSL For Secure ODBC connections</link> for
more information regarding this.</para></listitem>
-->
<listitem><para>When the configuration is complete, and indeed at any time
you are satisfied with the configuration press the <emphasis>Finish</emphasis>
button to save the DSN.</para></listitem>
</orderedlist>
</sect2>
&secureodbc;
<sect2 id="virtmanconfodbcdsnunix"><title>Manually configuring a Virtuoso ODBC DSN on Unix</title>
<para>If you have <ulink url="http://www.iodbc.org">iODBC</ulink> installed, you can configure Virtuoso data sources by
adding the following entry into the relevant .odbc.ini file. Usually it is the value of the ODBCINI
environment variable or $HOME/.odbc.ini:
</para>
<para>Sample DSN:
</para>
<programlisting><![CDATA[
[LocalVirt]
Driver=/usr/local/lib/virtodbc_32.so
# absolute path to the shared object
Address=localhost:1111
# host and port of the Virtuoso server
]]></programlisting>
<para>If the application that will load the ODBC driver is multithreaded, use the virtodbc32_r.so driver instead.
</para>
<sect3 id="virtmanconfodbcdsnunixlink"><title>Linking Client Applications</title>
<para>
The isql and other utilities are linked directly with the Virtuoso client code. See the Makefiles for the
libraries used. These are identical in function with the ODBC driver but accept a host:port in the place of
a data-source name to be resolved from the odbc ini file.
</para>
<para>Generally applications should pass via ODBC. Directly linking with the ODBC driver shared object
is also possible.
</para>
</sect3>
<sect3 id="virtmanconfodbcdsnunixjdbc"><title>JDBC</title>
<para>If you specified:</para>
<programlisting><![CDATA[
--with-jdbc3=<path of JDK>
]]></programlisting>
<para>
to the configure in the installation root directory, running make will produce the files
libsrc/JDBCDriverType4/virtjdbc3.jar and virtjdbc3ssl.jar. These can be placed on the
Java class path. See <link linkend="VirtuosoDriverJDBC">Virtuoso JDBC Documentation</link> for URL formats etc.
</para>
</sect3>
</sect2>
<sect2 id="odbccompliance"><title>ODBC Compliance</title>
<para>The Virtuoso Driver for ODBC conforms to both the ODBC
1.x,2.x,and 3.x versions of the ODBC specification, it implements Core, Level 1, Level 2,
and Extensions functionality. It also has a native support for the wide versions of the
ODBC API (e.g. SQLColumnsW) in Windows. This driver enables you to communicate with local or remote
Virtuoso servers across any combination of platforms supported by Virtuoso.</para>
<sect3 id="odbccompliance"><title>ODBC API implementation details</title>
<sect4 id="SQLAllocHandle"><title>SQLAllocHandle</title>
<para>Virtuoso ODBC driver does not allow allocation and usage of
explicitly allocated descriptor handles. That is why the
SQLAllocHandle (SQL_HANDLE_DESC) will return an error.</para>
</sect4>
<sect4 id="SQLBulkOperations"><title>SQLBulkOperations</title>
<para>Only the SQL_ADD operation is supported.</para>
</sect4>
<sect4 id="SQLColAttributes"><title>SQLColAttributes</title>
<para>The virtuoso ODBC driver does not return information for the
following attributes:</para>
<itemizedlist>
<listitem>
<formalpara>
<title>SQL_COLUMN_TABLE_NAME</title>
<para>Returns an empty string instead</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>SQL_COLUMN_OWNER_NAME</title>
<para>Returns an empty string instead</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>SQL_COLUMN_QUALIFIER_NAME</title>
<para>Returns an empty string instead</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>SQL_COLUMN_CASE_SENSITIVE</title>
<para>Returns 1 instead</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>SQL_COLUMN_AUTO_INCREMENT</title>
<para>Returns 0 instead</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>SQL_COLUMN_MONEY</title>
<para>Returns 0 instead</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>SQL_COLUMN_UNSIGNED</title>
<para>Returns 0 instead</para>
</formalpara>
</listitem>
</itemizedlist>
</sect4>
<sect4 id="SQLDriverConnect"><title>SQLDriverConnect</title>
<para>The Virtuoso ODBC driver recognizes the following
SQLDriverConnect connection string keywords:</para>
<itemizedlist>
<listitem>
<formalpara>
<title>DSN</title>
<para>The data source name.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>HOST</title>
<para>The virtuoso server host specification (in the form : [<hostname>[:]][<portnumber>]</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>UID</title>
<para>The virtuoso user ID used to connect</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>PWD</title>
<para>The login password used to connect</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>DATABASE</title>
<para>The qualifier to use when connected (overrides the user's default qualifier)</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>CHARSET</title>
<para>The name of the character set to use for wide/narrow conversions</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>DAYLIGHT</title>
<para>Boolean parameter (1/0). When ON (1) it takes into account the
client OS daylight savings settings.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>ENCRYPT</title>
<para>String parameter (file name or "1"). Specifies how the ODBC
connection will be encrypted. see the <link linkend="x509odbcclient">Using
SSL For Secure ODBC connections</link> for details.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>PWDCLEAR</title>
<para>Integer parameter (default to 0). Specifies how the password
will be sent over the wire. 0 - send digest of the password,
1 - send password in cleartext, 2 - send password garbaled.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>SERVERCERT</title>
<para>String parameter (file name). Specifies the path for the
CA list used to verify the server's certificate (in PEM format).
see the <link linkend="x509odbcclient">Using
SSL For Secure ODBC connections</link> for details.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>FORCE_DBMS_NAME</title>
<para>String parameter (default "OpenLink Virtuoso"). When set it
alters the result of SQLGetInfo (SQL_DBMS_NAME).</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>NoSystemTables</title>
<para>Boolean parameter (1/0) (default 0). When set it
alters the result of SQLTables () so that it won't find or return
tables of type SYSTEM TABLE.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>IsolationLevel</title>
<para>String parameter ("Read Uncommitted"/"Read Committed"/"Repeatable Read"/"Serializable").
When set it specifies the initial transaction isolation mode for that connection.</para>
</formalpara>
</listitem>
</itemizedlist>
</sect4>
<sect4 id="SQLGetEnvAttr"><title>SQLGetEnvAttr</title>
<para>The SQL_ATTR_OUTPUT_NTS does not have any effect on the
Virtuoso driver. It allows the value to be set and retrieved
but with no further effect.</para>
</sect4>
<sect4 id="SQLNativeSql"><title>SQLNativeSql</title>
<para>All ODBC syntax is parsed server side. The native SQL syntax for
Virtuoso is the ODBC syntax.</para>
</sect4>
<sect4 id="not_supp"><title>Not Supported ODBC API functions</title>
<para>Virtuoso ODBC driver does not support the following ODBC API
functions:</para>
<itemizedlist>
<listitem><para>SQLCopyDesc</para></listitem>
</itemizedlist>
</sect4>
</sect3>
</sect2>
<!-- ======================================== -->
<sect2 id="VScrlCURSORS">
<title>Virtuoso Scrollable Cursor Engine</title>
<para>Virtuoso implements server side scrollable cursors.
ODBC 2.0, ODBC 3.5 and JDBC 2.0 API's are supported.
</para>
<para>Cursor types include:</para>
<itemizedlist>
<listitem>
<formalpara>
<title>Forward only</title>
<para>This is the default, non-scrollable cursor.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>Static</title>
<para>The cursor's evaluation is computed when the cursor statement is first executed.
Positioned operations are possible but their effect will not show nor will changes be detected.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>Keyset</title>
<para>When the cursor is opened a keyset is built. Rows within the keyset
can be fetched and modified by positioned operations. Changes will show when refreshing
data and changes by other transactions will be detected for update and delete.
Inserts by the same or different transaction will not appear.
A keyset cursor may have a finite keyset size. When scrolling outside of
the given keyset the keyset will shift to cover the new rows.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>Dynamic</title>
<para>A dynamic cursor will reflect all changes by the same and different transactions.
The dynamic cursor's evaluation is constructed as needed, hence it generally has
less overhead than other types of cursors.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>Mixed</title>
<para>A mixed cursor is a combination of a keyset-driven cursor and a dynamic cursor.
It is used when the result set is too large to reasonably generate a keyset for the entire result set.
Mixed cursors use a keyset smaller than the entire result set but larger than the rowset.
</para>
<para>
While the application is scrolling within the keyset, the behavior is keyset-driven.
When the application scrolls beyond the keyset, the behavior becomes dynamic to fetch
the requested rows and generate a new keyset.
The behavior then reverts back to keyset-driven within that keyset, as before.
</para>
</formalpara>
</listitem>
</itemizedlist>
<sect3 id="FwdOnlyCursors">
<title>Forward Only Cursors</title>
<para>
A forward only cursor is substantially more efficient than a scrollable
cursor. It however does not allow positioned operations (the WHERE CURRENT OF SQL phrase),
or SQLSetPos. The SQLExtendedFetch function is supported but only the SQL_FETCH_NEXT
fetch type is then allowed.
</para>
</sect3>
<sect3 id="CursorOperation">
<title>Cursor Operations</title>
<para>Virtuoso supports all ODBC scrollable cursor operations. These include
</para>
<formalpara>
<title>SQLExtendedFetch / SQLScrollFetch fetch type</title>
<itemizedlist>
<listitem>
<para>SQL_FETCH_FIRST</para>
</listitem>
<listitem>
<para>SQL_FETCH_LAST</para>
</listitem>
<listitem>
<para>SQL_FETCH_NEXT</para>
</listitem>
<listitem>
<para>SQL_FETCH_PRIOR</para>
</listitem>
<listitem>
<para>SQL_FETCH_RELATIVE</para>
</listitem>
<listitem>
<para>SQL_FETCH_ABSOLUTE</para>
</listitem>
<listitem>
<para>SQL_FETCH_BOOKMARK</para>
</listitem>
</itemizedlist>
</formalpara>
<formalpara>
<title>SQLSetPos operations</title>
<itemizedlist>
<listitem>
<para>SQL_POSITION</para>
</listitem>
<listitem>
<para>SQL_REFRESH</para>
</listitem>
<listitem>
<para>SQL_ADD</para>
</listitem>
<listitem>
<para>SQL_UPDATE</para>
</listitem>
<listitem>
<para>SQL_DELETE</para>
</listitem>
</itemizedlist>
</formalpara>
<para>
Positioned SQL statements, i.e. the WHERE CURRENT OF clause, is supported for
scrollable cursors.
</para>
</sect3>
<sect3 id="CursorOptions">
<title>Cursor Options</title>
<para>The cursor options
<itemizedlist>
<listitem>
<para>SQL_CURSOR_TYPE</para>
</listitem>
<listitem>
<para>SQL_CONCURRENCY</para>
</listitem>
<listitem>
<para>SQL_KEYSET_SIZE</para>
</listitem>
<listitem>
<para>Cursor name (SQLSetCursorName)</para>
</listitem>
</itemizedlist>
have to be set before a SQLPrepare or SQLExecDirect.
</para>
<para>
The SQL_ROWSET_SIZE can be varied while a cursor is open.
</para>
</sect3>
<sect3 id="CursorsTransactions">
<title>Cursors and Transactions</title>
<para>
All forward only or scrollable cursors survive committing or rolling back transactions.
A cursor maintains its position over a transaction's end. Hence the
next fetch operation will resume from the correct place. If a dynamic cursor's current row / rowset is
deleted, the cursor will continue from the next greater / lesser row in the order of the cursor's
ordering columns. This also applies to mixed mode (keyset with finite keyset size)
cursors scrolling outside of the keyset bounds. A forward only cursor will retain its logical position across commit/rollback.
</para>
<para>
The SQL_CONCURRENCY values of SQL_CONCUR_READ_ONLY and SQL_CONCUR_LOCK
cause Virtuoso to lock the rows in the keyset / rowset in shared or exclusive mode, respectively.
</para>
</sect3>
<sect3 id="OptimisticConcurrency">
<title>Optimistic Concurrency Control</title>
<para>
A scrollable cursor may have a SQL_CONCURRENCY setting of SQL_CONCUR_VALUES. This
enables optimistic concurrency control. This is a mechanism which will reflect an
update or delete of a row if the row has been modified by a third party after the time the
application last read the row.
</para>
<para>
A 'updated meanwhile' condition detected in this manner will prevent the operation and
return a SQL state of 01001 with SQL_SUCCESS_WITH_INFO from SQLSetPos.
</para>
<para>
The updates and deletes made through SQLSetPos are still subject to being committed or rolled
back by normal transaction control. The 01001 state does not prevent the current transaction
from committing.
</para>
<para>
The 01001 state is only detected if the update or delete is made by SQLSetPos and the row
at hand has been changed by any statement of any transaction. If the update of updated
operation is carried out by any other operation than SQLSetPos of the statement that last read
the value the condition cannot be detected.
</para>
<para>
Note that the time between the last read and the SQLSetPos update can be long
and can span multiple transactions.
</para>
</sect3>
<sect3 id="CursorInfo">
<title>Cursor Information</title>
<table colsep="1" frame="all" rowsep="0" shortentry="0" tocentry="1" tabstyle="decimalstyle" orient="land" pgwide="0">
<title>Cursor Support</title>
<tgroup align="char" charoff="50" char="." cols="4">
<colspec align="left" colnum="1" colsep="0" colwidth="20pc"/>
<thead>
<row>
<entry/>
<entry>Static</entry>
<entry>Keyset</entry>
<entry>Dynamic</entry>
</row>
</thead>
<tbody>
<row>
<entry>SQLRowCount</entry>
<entry>x</entry>
<entry>x</entry>
<entry/>
</row>
<row>
<entry>SQL_BOOKMARK</entry>
<entry>x</entry>
<entry>x</entry>
<entry>x</entry>
</row>
<row>
<entry>SQL_ROW_NUMBER</entry>
<entry>x</entry>
<entry>x</entry>
<entry/>
</row>
<row>
<entry>reflect update</entry>
<entry/>
<entry>x</entry>
<entry>x</entry>
</row>
<row>
<entry>reflect delete</entry>
<entry/>
<entry/>
<entry>x</entry>
</row>
<row>
<entry>reflect inx</entry>
<entry/>
<entry/>
<entry>x</entry>
</row>
<row>
<entry>Notice update</entry>
<entry>x</entry>
<entry>x</entry>
<entry>x</entry>
</row>
<row>
<entry>Notice delete</entry>
<entry>x</entry>
<entry>x</entry>
<entry>x</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
SQLRowCount is set after the initial SQLExecute. This is the actual row count or the keyset size
for a mixed mode cursor. A dynamic cursor does not know this since it builds the evaluation as
needed.
</para>
<para>
All cursors support bookmarks.
</para>
<para>
The SQL_ROW_NUMBER is the ordinal number of the current row in the
cursor's evaluation. A dynamic cursor cannot know this, as the scrolling may
start from end and rows may appear on either side of the current row while the cursor is open.
</para>
<para>
'reflect' means that the new values or added / deleted rows
appear when re-scrolling over the rows. A deletion is reflected by
omitting the row.
</para>
<para>
'notice' means that the row is flagged by SQL_UPDATE, SQL_DELETED
or SQL_ADDED in the SQLExtendedFetch status array when the cursor re-scrolls over the
rows in question.
</para>
</sect3>
<sect3 id="CursorsVDB">
<title>Cursors and Virtual Database</title>
<para>
The cursor subsystem modifies the cursor's defining select statement to
make various backward and forward read statements, update and delete statements etc.
These transformations can be seen through the explain function.
</para>
<para>
Since cursors are implemented by generating SQL statements these work transparently
against remote database, independently of their possible native cursor support.
</para>
</sect3>
<sect3 id="CursorSpecialCases">
<title>Cursor Special Cases</title>
<para>
SQL SELECT statements fall in two categories: Simple, which consist of
one or more tables, an arbitrary WHERE clause and an optional ORDER BY, and Complex, which includes
all other SELECT's, e.g. ones with GROUP BY, derived tables, full outer joins, UNION's etc.
</para>
<para>
A simple statement can easily be modified to read backwards or forwards from a given point. Also,
each result row of a simple statement has a physical counterpart, or many physical counterparts
for a join. Having a physical counterpart makes it possible to define the meaning of a positioned
update or delete. A GROUP BY is a counter-example.
</para>
<para>
All complex SQL statements occurring as cursors are processed as static
cursors regardless of the declared cursor type.
</para>
</sect3>
<sect3 id="CursorPerf">
<title>Cursors and Performance</title>
<para>
If a cursor's ordering corresponds to an ordering in an index, dynamic cursors will generally perform
best. This is understandable since the engine can quickly locate
the current row based on an index and then just read backward or forward on that index.
On the other hand, if the result set is very sparsely spread over the table or if
there is no ordering index dynamic cursors will have a substantial penalty.
</para>
<para>
If used as a forward only cursor in a single transaction, a dynamic cursor is only some
30% slower than a forward only cursor.
</para>
<para>
A static or keyset cursor has a relatively long execute time since the initial execute
will make the entire keyset. The initial execute of a dynamic cursor is instantaneous
since the fetch operations will do the work as needed.
</para>
<para>
With most off the shelf applications, e.g. Microsoft ADO, static and keyset cursors
are preferable because the applications may rely on row counts and row numbers which
are not known for dynamic cursors.
</para>
<para>
Positioned operations are not affected by cursor type.
</para>
</sect3>
</sect2>
<!-- ======================================== -->
<sect2 id="CONN_STMT_OPTIONS">
<title>Effect of Connection & Statement Options</title>
<sect3 id="ConnOpt">
<title>Connection Options</title>
<sect4 id="SQL_AUTOCOMMIT">
<title>SQL_AUTOCOMMIT</title>
<para>
The autocommit option is set at the connection level and affects
every statement executed after it being set. Setting the option
does not communicate itself with the server and is therefore fast.
</para>
<para>
Autocommit is on by default. Autocommitting SELECT statements are executed
with read committed isolation. This is appropriate since any update
based on the autocommitting read would be in a different transaction and hence
would block to wait for access to the selected row. Also re-evaluating
a select in autocommit mode would read the data in a different transaction.
Hence there is no point in repeatable read isolation for autocommitting
cursors. Cursors inside procedures have the normal repeatable read isolation
regardless of whether the procedure was called in autocommit mode.
</para>
<para>
When an autocommitting statement starts it is executed in the transaction
That is the connection's current transaction when it is received. Before
starting the autocommitting statement sets the connection's current
transaction to a new one. In this manner a client can issue multiple
asynchronous autocommitting statements at the same time and the statements
will execute concurrently, each in its own transaction.
</para>
<para>
If array parameters are used in a statement on an autocommitting
connection each parameter row will be processed in its own transaction
in sequential order. Multiple Asynchronous statements must be used to
execute one client's statements in parallel.
</para>
<para>To commit or roll back a transaction in manual-commit mode, an
application should call SQLEndTran. Applications should not attempt
to commit or roll back transactions by executing COMMIT or ROLLBACK
statements with SQLExecute or SQLExecDirect. The effects of doing
this are undefined.</para>
</sect4>
<sect4 id="SQL_TXN_ISO">
<title>SQL_TXN_ISOLATION</title>
<para>
This option allows all the values defined in ODBC,
</para>
<para>
The isolation of an operation is the property of the operation rather than
of the transaction within which it takes place. Once an operation
has started, e.g. a cursor has been opened, its isolation cannot be changed.
</para>
<para>
The value of this option will affect any subsequently executed statement.
Note that setting this option to different values during a transaction will work,
thus a transaction can have cursors with different isolations although that
is presumably not the intention of the ODBC specification.
</para>
<para>
See the transaction model for a definition of the different isolation levels.
</para>
<para>
A statement in autocommit mode executes
in the same transaction as the previous statement. The transaction is
committed when the statement successfully completes. The next statement in
the connection will execute in the fresh transaction that was associated to
the connection at the start of the previous autocommitting statement.
</para>
<para>
As a consequence of this multiple concurrent autocommitting transactions may execute
on the same connection at the same time.
</para>
<para>
Statements executed with array parameters execute each set of
parameters as a separate transaction if the connection is in autocommit
mode.
</para>
</sect4>
<sect4 id="SQL_ACCESS_MODE">
<title>SQL_ACCESS_MODE</title>
<para>
This has the effect of reversing any SQL_CONCUR_LOCK concurrency to SQL_CONCUR_READ_ONLY.
The statement option's value is not changed though.
</para>
</sect4>
<sect4 id="SQL_CURRENT_QUAL">
<title>SQL_CURRENT_QUALIFIER</title>
<para>
This sets or gets the current qualifier. The initial
value is obtained from the server at connect time. The values reflect the
effects of any USE statements.
</para>
</sect4>
<sect4 id="SQL_NO_CHAR_C_ESCAPE">
<title>SQL_NO_CHAR_C_ESCAPE (=5002)</title>
<para>
This has the same effect as the NO_CHAR_C_ESCAPE option in the SET statement. It takes boolean int values (0/non-0)
</para>
</sect4>
<sect4 id="SQL_CHARSET">
<title>SQL_CHARSET (=5003)</title>
<para>
This has the same effect as the CHARSET option in SET statement. It takes string values (the name of the
character set to use).
</para>
</sect4>
<sect4 id="SQL_ENCRYPT_CONNECTION">
<title>SQL_ENCRYPT_CONNECTION (=5004)</title>
<para>
Usable only with the Virtuoso CLI (because the ODBC/iODBC driver manager does not pass-through the custom
options to the driver on SQLConnect/SQLDriverConnect). When set to the string "1" means use SSL but no
X509 certificates. Setting it to a NULL (default) means no encryption of the ODBC connection.
Any other string is treated as a file name of one PKCS12 package to get the data from for establishing an
encrypted SSL connection using X509 certificates (see the -E/-X ISQL options).
</para>
</sect4>
<sect4 id="SQL_SHUTDOWN_ON_CONNECT">
<title>SQL_SHUTDOWN_ON_CONNECT (=5005)</title>
<para>
Usable only with the Virtuoso CLI (because the ODBC/iODBC driver manager does not pass through the custom
options to the driver on SQLConnect/SQLDriverConnect). Shuts down the server on connection after authenticating
the DBA user (see the -K ISQL option).
</para>
</sect4>
</sect3>
<sect3 id="SQLSetStmtOption">
<title>SQLSetStmtOption Statement Options</title>
<para>
Virtuoso supports all ODBC 2.x and ODBC 3.x statement options.
The following options are mentioned below due to implementation specific
details.
</para>
<sect4 id="SQLConcurrency">
<title>SQL_CONCURRENCY</title>
<para>
The supported values are SQL_CONCUR_READ_ONLY, SQL_CONCUR_LOCK and SQL_CONCUR_VALUES, the
last option is only available for scrollable cursors. A select statement
with SQL_CONCUR_READ_ONLY will make shared locks when locking for repeatable
read or serializable transactions. The SQL_CONCUR_LOCK for a select statement
will cause it to make exclusive locks, as if it had the FOR UPDATE clause specified.
</para>
<para>
See the section on scrollable cursors for the effect of SQL_CONCUR_VALUES. For
all statements except scrollable cursors this value reverts to SQL_CONCUR_READ_ONLY.
</para>
<para>
Any searched update or delete statements will make exclusive locks in all cases.
</para>
</sect4>
<sect4 id="SQLMaxRows">
<title>SQL_MAX_ROWS</title>
<para>
This option only affects static cursors.
</para>
</sect4>
<sect4 id="SQLTxnTimeout">
<title>SQL_TXN_TIMEOUT</title>
<para>
This is an extension that allows setting a time limit on the current transaction.
The time limit starts at the execution of the statement specifying this option.
The transaction will terminate the indicated number of seconds after the execute
whether the statement has completed or not.</para>
</sect4>
<sect4 id="SQLPrefetchSize">
<title>SQL_PREFETCH_SIZE</title>
<para>
This is an extension option that controls how many rows of a forward only cursor are
prefetched by the execute and fetch calls. A high value is advantageous for
long consecutive reads since it cuts down on the number of client server messages
exchanged. On the other hand a large value can result in unnecessary data transfer
and locking if only the first few rows of a cursor are fetched. A value of -1 will
cause the entire rowset to be fetched at the execute, so that no matter the select size, only
one message is exchanged. The default value is 20. This can also be set in the virtuoso.ini file.
</para>
<para>
A select with array parameters will always work as with a SQL_PREFETCH_SIZE of -1, meaning that
all the result sets are computed and sent to the client by the SQLExecute
call that opens the cursor.
</para>
</sect4>
<sect4 id="SQLCursorType">
<title>SQL_CURSOR_TYPE</title>
</sect4>
<sect4 id="KeySetSize">
<title>SQL_KEYSET_SIZE</title>
</sect4>
<sect4 id="SQLConcur">
<title>SQL_CONCURRENCY</title>
</sect4>
<para>
The cursor type options should be set before preparing a statement.
Other options may be set at any time. The rowset and prefetch options should not be modified after executing a SELECT.
</para>
<sect4 id="SQLGETLASTSERIAL">
<title>SQL_GETLASTSERIAL</title>
<para>
This is an extension that returns the last assigned identity column
value. The return buffer pvParam is of type SQLINTEGER. For this to be
meaningful, the statement in question must be an INSERT into a table
that has an identity column. Note that if there are more than one
identity columns or if triggers make inserts with identity columns the
value will be undefined.
</para>
</sect4>
</sect3>
</sect2>
<!-- ======================================== -->
<sect2 id="EFFICIENTAPI">
<title>Efficient Use of API</title>
<para>
DO NOT USE SQLExecDirect. If a statement is executed more than once it
is much faster to prepare the statement with SQLPrepare and then use
SQLExecute repeatedly. The system only compiles the statement once,
therefore there is no parsing overhead for repeatedly compiling the
same text.
</para>
<para>
Array parameters for insert, update or single row selects are about
twice as fast as the same operations on a single parameter set.
</para>
<para>
The OR connective in SQL can result in slow queries with extensive
locking.
</para>
<para>
Autocommit should be used when possible, i.e. make the last statement of
a transaction autocommitting to avoid having to commit the transaction
as a separate operation.
</para>
</sect2>
<sect2 id="EXECPYTHONSCRIPT">
<title>Executing SQL from Python script</title>
<para>In order to execute SQL from Python script, you need to add the following lines to the /etc/odbc.ini
file:</para>
<programlisting><![CDATA[
[Local Virtuoso]
Driver = /PREFIX/lib/virtodbc_r.so
Address = localhost:1111
]]></programlisting>
<para>where PREFIX is replaced by the full path where Virtuoso is installed and also assuming that
is used let's say port 1111 in virtuoso.ini (which is set by default).
</para>
<para>Then you should be able to connect with:</para>
<programlisting><![CDATA[
c = pyodbc.connect('DSN=Local Virtuoso;UID=dba;PWD=dba')
]]></programlisting>
</sect2>
<sect2 id="odbcimplementationext">
<title>Extensions</title>
<sect3 id="virtodbcsparql"><title>Virtuoso ODBC RDF Extensions for SPASQL</title>
<para>The Virtuoso ODBC Driver adds a number of defines to the ODBC API to allow an ODBC compliant
application to query meta information on SPASQL queries.</para>
<para>If the application uses the iODBC Driver Manager V3.52.7 or higher, it can simply include the
iodbcext.h header file, which contains information on extensions of many ODBC drivers like DB2, SQL
Server and Virtuoso.</para>
<para>If however the application is compiled against another Driver Manager, like the Microsoft
Driver Manager on Windows, the following construction should to be used:</para>
<programlisting><![CDATA[
#ifdef WIN32
# include <windows.h>
#endif
#include <sql.h>
#include <sqlext.h>
#if defined (HAVE_IODBC)
#include <iodbcext.h>
#endif
/*
* Include Virtuoso ODBC extensions for SPASQL result set
*/
#if !defined (SQL_DESC_COL_DV_TYPE)
/*
* ODBC extensions for SQLGetDescField
*/
# define SQL_DESC_COL_DV_TYPE 1057L
# define SQL_DESC_COL_DT_DT_TYPE 1058L
# define SQL_DESC_COL_LITERAL_ATTR 1059L
# define SQL_DESC_COL_BOX_FLAGS 1060L
# define SQL_DESC_COL_LITERAL_LANG 1061L
# define SQL_DESC_COL_LITERAL_TYPE 1062L
/*
* Virtuoso - ODBC SQL_DESC_COL_DV_TYPE
*/
# define VIRTUOSO_DV_DATE 129
# define VIRTUOSO_DV_DATETIME 211
# define VIRTUOSO_DV_DOUBLE_FLOAT 191
# define VIRTUOSO_DV_IRI_ID 243
# define VIRTUOSO_DV_LONG_INT 189
# define VIRTUOSO_DV_NUMERIC 219
# define VIRTUOSO_DV_RDF 246
# define VIRTUOSO_DV_SINGLE_FLOAT 190
# define VIRTUOSO_DV_STRING 182
# define VIRTUOSO_DV_TIME 210
# define VIRTUOSO_DV_TIMESTAMP 128
# define VIRTUOSO_DV_TIMESTAMP_OBJ 208
/*
* Virtuoso - ODBC SQL_DESC_COL_DT_DT_TYPE
*/
# define VIRTUOSO_DT_TYPE_DATETIME 1
# define VIRTUOSO_DT_TYPE_DATE 2
# define VIRTUOSO_DT_TYPE_TIME 3
/*
* Virtuoso - ODBC SQL_DESC_COL_BOX_FLAGS
*/
#define VIRTUOSO_BF_IRI 0x1
#define VIRTUOSO_BF_UTF8 0x2
#define VIRTUOSO_BF_DEFAULT_ENC 0x4
#endif
]]></programlisting>
<sect4 id="virtodbcsparqlapi"><title>API</title>
<sect5 id="virtodbcsparqlapisgdf"><title>SQLGetDescField</title>
<para>Before the application can retrieve the column meta data using <computeroutput>SQLGetDescField</computeroutput>,
it first needs to retrieve the correct descriptor handle attached to the statement handle:</para>
<programlisting><![CDATA[
SQLHDESC hdesc = NULL;
SQLRETURN rc;
rc = SQLGetStmtAttr (hstmt, SQL_ATTR_IMP_ROW_DESC, &hdesc, SQL_IS_POINTER, NULL);
if (!SQL_SUCCEEDED(rc))
{
/* Handle error */
}
]]></programlisting>
<formalpara>
<title>SQLGetDescField - SQL_DESC_COL_DV_TYPE</title>
<para>Retrieves the datatype of a field.</para>
<programlisting><![CDATA[
SQLINTEGER dvtype;
SQLRETURN rc;
rc = SQLGetDescField (hdesc, colNum, SQL_DESC_COL_DV_TYPE, &dvtype, SQL_IS_INTEGER, NULL);
]]></programlisting>
<para>If this call returns <computeroutput>SQL_SUCCESS</computeroutput> or <computeroutput>SQL_SUCCESS_WITH_INFO</computeroutput>, the dvtype variable will contain
the underlying Virtuoso datatype as indicated in the following table:</para>
<programlisting><![CDATA[
#define VIRTUOSO_DV_DATE 129
#define VIRTUOSO_DV_DATETIME 211
#define VIRTUOSO_DV_DOUBLE_FLOAT 191
#define VIRTUOSO_DV_IRI_ID 243
#define VIRTUOSO_DV_LONG_INT 189
#define VIRTUOSO_DV_NUMERIC 219
#define VIRTUOSO_DV_RDF 246
#define VIRTUOSO_DV_SINGLE_FLOAT 190
#define VIRTUOSO_DV_STRING 182
#define VIRTUOSO_DV_TIME 210
#define VIRTUOSO_DV_TIMESTAMP 128
#define VIRTUOSO_DV_TIMESTAMP_OBJ 208
]]></programlisting>
</formalpara>
<formalpara>
<title>SQLGetDescField - SQL_DESC_COL_DT_DT_TYPE</title>
<para>Retrieves the date subtype of a field.</para>
<programlisting><![CDATA[
SQLINTEGER dv_dt_type;
SQLRETURN rc;
rc = SQLGetDescField (hdesc, colNum, SQL_DESC_COL_DT_DT_TYPE, &dv_dt_type, SQL_IS_INTEGER, NULL);
]]></programlisting>
<para>If this call returns <computeroutput>SQL_SUCCESS</computeroutput> or <computeroutput>SQL_SUCCESS_WITH_INFO</computeroutput>, the dttype variable will contain the
underlying Virtuoso date subtype as indicated in the following table:</para>
<programlisting><![CDATA[
#define VIRTUOSO_DT_TYPE_DATETIME 1
#define VIRTUOSO_DT_TYPE_DATE 2
#define VIRTUOSO_DT_TYPE_TIME 3
]]></programlisting>
</formalpara>
<formalpara>
<title>SQLGetDescField - SQL_DESC_COL_LITERAL_ATTR</title>
<para>Retrieves the literal attributes associated with the field.</para>
<programlisting><![CDATA[
SQLINTEGER littype;
SQLINTEGER lang, type;
SQLRETURN rc;
rc = SQLGetDescField (hdesc, colNum, SQL_DESC_COL_DT_DT_TYPE, &littype, SQL_IS_INTEGER, NULL);
lang = (littype >> 16) & 0xFFFF;
type = littype & 0xFFFF;
]]></programlisting>
<para>If this call returns <computeroutput>SQL_SUCCESS</computeroutput> or <computeroutput>SQL_SUCCESS_WITH_INFO</computeroutput>,
the littype variable will contain the encoded language and rdf type information of the field.</para>
<para>These numbers are uniq to the database the client has connected to, and correspond to information
in the <computeroutput>DB.DBA.RDF_LANGUAGE</computeroutput> and <computeroutput>DB.DBA.RDF_DATATYPE</computeroutput>
tables:</para>
<programlisting><![CDATA[
select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = ?
]]></programlisting>
<para>and</para>
<programlisting><![CDATA[
select RDT_QNAME from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = ?
]]></programlisting>
<note><title>Note:</title>
<para>This call is deprecated in favor of using the <computeroutput>SQL_DESC_COL_LITERAL_LANG</computeroutput>
and <computeroutput>SQL_DESC_LITERAL_TYPE</computeroutput> options of <computeroutput>SQLGetDescField</computeroutput>
which caches these lookups to speed up describe operations.</para>
</note>
</formalpara>
<formalpara>
<title>SQLGetDescField - SQL_DESC_COL_BOX_FLAGS</title>
<para>Retrieves the flags associated with the field:</para>
<programlisting><![CDATA[
SQLINTEGER flags;
SQLRETURN rc;
rc = SQLGetDescField (hdesc, colNum, SQL_DESC_COL_BOX_FLAGS, &flags, SQL_IS_INTEGER, NULL);
]]></programlisting>
<para>If this call returns <computeroutput>SQL_SUCCESS</computeroutput>
or <computeroutput>SQL_SUCCESS_WITH_INFO</computeroutput>, the following
bitmasks can be used to determine the representation of the field:</para>
<programlisting><![CDATA[
#define VIRTUOSO_BF_IRI 0x1
#define VIRTUOSO_BF_UTF8 0x2
#define VIRTUOSO_BF_DEFAULT_ENC 0x4
for example:
flags description
0 field contains a Latin1 encoded literal string
1 field contains an IRI (always UTF-8 encoded)
2 field contains an UTF-8 encoded literal string
3 field contains an UTF-8 encoded IRI (should not happen)
]]></programlisting>
</formalpara>
<formalpara>
<title>SQLGetDescField - SQL_DESC_COL_LITERAL_LANG</title>
<para>Retrieves the language string for this field:</para>
<programlisting><![CDATA[
SQLCHAR langbuf[100];
SQLINTEGER len1;
SQLRETURN rc;
rc = SQLGetDescField (hdesc, colNum, SQL_DESC_COL_LITERAL_LANG, langbuf, sizeof (langbuf), &len1);
]]></programlisting>
<para>If this call returns <computeroutput>SQL_SUCCESS</computeroutput> or
<computeroutput>SQL_SUCCESS_WITH_INFO,</computeroutput>, the langbuf variable will contain
the language of the field.</para>
</formalpara>
<formalpara>
<title>SQLGetDescField - SQL_DESC_COL_LITERAL_TYPE</title>
<para>
Retrieves the data type string for this field:</para>
<programlisting><![CDATA[
SQLCHAR typebuf[100];
SQLINTEGER len2;
SQLRETURN rc;
rc = SQLGetDescField (hdesc, colNum, SQL_DESC_COL_LITERAL_TYPE, typebuf, sizeof (typebuf), &len2);
]]></programlisting>
<para>If this call returns <computeroutput>SQL_SUCCESS</computeroutput> or
<computeroutput>SQL_SUCCESS_WITH_INFO</computeroutput>, the typebuf variable will contain
the rdf type of the field.</para>
</formalpara>
</sect5>
</sect4>
<sect4 id="virtodbcsparqlevalnodes"><title>Evaluating Nodes</title>
<para>The following pseudo code evaluates the various type and flag information retrieved using
the above API calls and shows what kind of node a field is.</para>
<programlisting><![CDATA[
switch (dvtype)
{
case VIRTUOSO_DV_STRING:
{
if (flag == 1)
{
if (strncmp ((char *) data, "_:", 2) == 0)
{
/* node is a Turtle style named BNode */
}
else
{
/* node is an URI string */
}
}
else
{
if (strncmp ((char *) data, "nodeID://", 9) == 0)
{
/* node is a BNode */
}
else
{
/* node is a string literal */
}
}
break;
}
case VIRTUOSO_DV_RDF:
/* node is a typed literal with possible lang and type */
break;
case VIRTUOSO_DV_LONG_INT:
/* node is a literal http://www.w3.org/2001/XMLSchema#integer */
break;
case VIRTUOSO_DV_SINGLE_FLOAT:
/* node is a literal http://www.w3.org/2001/XMLSchema#float */
break;
case VIRTUOSO_DV_DOUBLE_FLOAT:
/* node is a literal http://www.w3.org/2001/XMLSchema#double */
break;
case VIRTUOSO_DV_NUMERIC:
/* node is a literal http://www.w3.org/2001/XMLSchema#decimal */
break;
case VIRTUOSO_DV_TIMESTAMP:
case VIRTUOSO_DV_DATE:
case VIRTUOSO_DV_TIME:
case VIRTUOSO_DV_DATETIME:
switch (dv_dt_type)
{
case VIRTUOSO_DT_TYPE_DATE:
/* node is a literal http://www.w3.org/2001/XMLSchema#date */
break;
case VIRTUOSO_DT_TYPE_TIME:
/* node is a literal http://www.w3.org/2001/XMLSchema#time */
break;
default:
/* node is a literal http://www.w3.org/2001/XMLSchema#dateTime */
break;
}
break;
case VIRTUOSO_DV_IRI_ID:
/*
* node is an IRI ID
*
* This type is only returned in output:valmode "LONG"
* It needs to be translated into a literal string using the
* ID_TO_IRI() function as the value is database specific.
*/
break;
default:
/* unhandled type */
return NULL;
}
]]></programlisting>
</sect4>
<sect4 id="virtodbcsparqlexample"><title>Examples</title>
<para>The following program performs a SPARQL query against a Virtuoso Database using SPASQL. Note
that the connection parameters and the sparql query are compiled into the executable.</para>
<para>To compile it on Linux against iODBC the following command can be used:</para>
<programlisting><![CDATA[
gcc -o odbc_iri -I/usr/local/iODBC odbc_iri.c -L/usr/local/iODBC/lib -liodbc -ldl
]]></programlisting>
<para>It can then be called as:</para>
<programlisting><![CDATA[
./odbc_iri
]]></programlisting>
<para>which will print out the first 50 triples from the database in N3 format.</para>
<para>Here it is the source code:</para>
<programlisting><![CDATA[
/*
* odbc_iri.c
*
* This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
* project.
*
* Copyright (C) 1998-2018 OpenLink Software
*
* This project is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; only version 2 of the License, dated June 1991.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdio.h>
#include <string.h>
#ifdef WIN32
# include <windows.h>
#endif
#include <sql.h>
#include <sqlext.h>
#if defined (HAVE_IODBC)
#include <iodbcext.h>
#endif
/*
* Include Virtuoso ODBC extensions for SPASQL result set
*/
#if !defined (SQL_DESC_COL_DV_TYPE)
/*
* ODBC extensions for SQLGetDescField
*/
# define SQL_DESC_COL_DV_TYPE 1057L
# define SQL_DESC_COL_DT_DT_TYPE 1058L
# define SQL_DESC_COL_LITERAL_ATTR 1059L
# define SQL_DESC_COL_BOX_FLAGS 1060L
# define SQL_DESC_COL_LITERAL_LANG 1061L
# define SQL_DESC_COL_LITERAL_TYPE 1062L
/*
* Virtuoso - ODBC SQL_DESC_COL_DV_TYPE
*/
# define VIRTUOSO_DV_DATE 129
# define VIRTUOSO_DV_DATETIME 211
# define VIRTUOSO_DV_DOUBLE_FLOAT 191
# define VIRTUOSO_DV_IRI_ID 243
# define VIRTUOSO_DV_LONG_INT 189
# define VIRTUOSO_DV_NUMERIC 219
# define VIRTUOSO_DV_RDF 246
# define VIRTUOSO_DV_SINGLE_FLOAT 190
# define VIRTUOSO_DV_STRING 182
# define VIRTUOSO_DV_TIME 210
# define VIRTUOSO_DV_TIMESTAMP 128
# define VIRTUOSO_DV_TIMESTAMP_OBJ 208
/*
* Virtuoso - ODBC SQL_DESC_COL_DT_DT_TYPE
*/
# define VIRTUOSO_DT_TYPE_DATETIME 1
# define VIRTUOSO_DT_TYPE_DATE 2
# define VIRTUOSO_DT_TYPE_TIME 3
/*
* Virtuoso - ODBC SQL_DESC_COL_BOX_FLAGS
*/
#define VIRTUOSO_BF_IRI 0x1
#define VIRTUOSO_BF_UTF8 0x2
#define VIRTUOSO_BF_DEFAULT_ENC 0x4
#endif
SQLHANDLE henv = SQL_NULL_HANDLE;
SQLHANDLE hdbc = SQL_NULL_HANDLE;
SQLHANDLE hstmt = SQL_NULL_HANDLE;
#define MAXCOLS 25
int
ODBC_Errors (char *where)
{
unsigned char buf[250];
unsigned char sqlstate[15];
/*
* Get statement errors
*/
while (SQLError (henv, hdbc, hstmt, sqlstate, NULL, buf, sizeof (buf), NULL) == SQL_SUCCESS)
{
fprintf (stdout, "STMT: %s || %s, SQLSTATE=%s\n", where, buf, sqlstate);
}
/*
* Get connection errors
*/
while (SQLError (henv, hdbc, SQL_NULL_HSTMT, sqlstate, NULL, buf, sizeof (buf), NULL) == SQL_SUCCESS)
{
fprintf (stdout, "CONN:%s || %s, SQLSTATE=%s\n", where, buf, sqlstate);
}
/*
* Get environment errors
*/
while (SQLError (henv, SQL_NULL_HDBC, SQL_NULL_HSTMT, sqlstate, NULL, buf, sizeof (buf), NULL) == SQL_SUCCESS)
{
fprintf (stdout, "ENV:%s || %s, SQLSTATE=%s\n", where, buf, sqlstate);
}
return -1;
}
int
ODBC_Disconnect (void)
{
if (hstmt)
SQLFreeHandle (SQL_HANDLE_STMT, hstmt);
hstmt = SQL_NULL_HANDLE;
if (hdbc)
SQLDisconnect (hdbc);
if (hdbc)
SQLFreeHandle (SQL_HANDLE_DBC, hdbc);
hdbc = SQL_NULL_HANDLE;
if (henv)
SQLFreeHandle (SQL_HANDLE_ENV, henv);
henv = SQL_NULL_HANDLE;
return 0;
}
int
ODBC_Connect (char *dsn, char *usr, char *pwd)
{
SQLRETURN rc;
/* Allocate environment handle */
rc = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
if (!SQL_SUCCEEDED (rc))
goto error;
/* Set the ODBC version environment attribute */
rc = SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
if (!SQL_SUCCEEDED (rc))
goto error;
/* Allocate connection handle */
rc = SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);
if (!SQL_SUCCEEDED (rc))
goto error;
/* Connect to data source */
rc = SQLConnect (hdbc, (SQLCHAR *) dsn, SQL_NTS, (SQLCHAR *) usr, SQL_NTS, (SQLCHAR *) pwd, SQL_NTS);
if (!SQL_SUCCEEDED (rc))
goto error;
/* Allocate statement handle */
rc = SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt);
if (!SQL_SUCCEEDED (rc))
goto error;
/* Successful connection */
return 0;
error:
/* Failed connection */
ODBC_Errors ("ODBC_Connect");
ODBC_Disconnect ();
return -1;
}
int
ODBC_PrintResult ()
{
char fetchBuffer[1000];
short numCols = 0;
short colNum;
SDWORD colIndicator;
UDWORD totalRows;
UDWORD totalSets;
SQLHANDLE hdesc = SQL_NULL_HANDLE;
SQLRETURN rc;
totalSets = 0;
do
{
/*
* Get the number of result columns for this cursor.
* If it is 0, then the statement was probably not a select
*/
rc = SQLNumResultCols (hstmt, &numCols);
if (!SQL_SUCCEEDED (rc))
{
ODBC_Errors ("SQLNumResultCols");
goto endCursor;
}
if (numCols == 0)
{
printf ("Statement executed.\n");
goto endCursor;
}
if (numCols > MAXCOLS)
numCols = MAXCOLS;
/*
* Print all the fields
*/
totalRows = 0;
while (1)
{
/*
* Fetch next record
*/
rc = SQLFetch (hstmt);
if (rc == SQL_NO_DATA_FOUND)
break;
if (!SQL_SUCCEEDED (rc))
{
ODBC_Errors ("Fetch");
break;
}
for (colNum = 1; colNum <= numCols; colNum++)
{
char buf[1000];
SQLINTEGER len;
int flag, dvtype;
/*
* Fetch this column as character
*/
rc = SQLGetData (hstmt, colNum, SQL_C_CHAR, fetchBuffer, sizeof (fetchBuffer), &colIndicator);
if (!SQL_SUCCEEDED (rc))
{
ODBC_Errors ("SQLGetData");
goto endCursor;
}
/*
* Get descriptor handle for this statement
*/
rc = SQLGetStmtAttr (hstmt, SQL_ATTR_IMP_ROW_DESC, &hdesc, SQL_IS_POINTER, NULL);
if (!SQL_SUCCEEDED (rc))
{
ODBC_Errors ("SQLGetStmtAttr");
goto endCursor;
}
/*
* Get data type of column
*/
rc = SQLGetDescField (hdesc, colNum, SQL_DESC_COL_DV_TYPE, &dvtype, SQL_IS_INTEGER, NULL);
if (!SQL_SUCCEEDED (rc))
{
ODBC_Errors ("SQLGetDescField");
goto endCursor;
}
/*
* Get flags
*/
rc = SQLGetDescField (hdesc, colNum, SQL_DESC_COL_BOX_FLAGS, &flag, SQL_IS_INTEGER, NULL);
if (!SQL_SUCCEEDED (rc))
{
ODBC_Errors ("SQLGetDescField");
goto endCursor;
}
/*
* Show NULL fields as ****
*/
if (colIndicator == SQL_NULL_DATA)
{
printf ("NULL");
}
else
{
if (flag & VIRTUOSO_BF_IRI)
printf ("<%s>", fetchBuffer); /* IRI */
else if (dvtype == VIRTUOSO_DV_STRING || dvtype == VIRTUOSO_DV_RDF)
printf ("\"%s\"", fetchBuffer); /* literal string */
else
printf ("%s", fetchBuffer); /* value */
if (dvtype == VIRTUOSO_DV_RDF)
{
rc = SQLGetDescField (hdesc, colNum, SQL_DESC_COL_LITERAL_LANG, buf, sizeof (buf), &len);
if (!SQL_SUCCEEDED (rc))
{
ODBC_Errors ("SQLGetDescField");
goto endCursor;
}
if (len)
printf ("@%.*s", (int) len, buf);
rc = SQLGetDescField (hdesc, colNum, SQL_DESC_COL_LITERAL_TYPE, buf, sizeof (buf), &len);
if (!SQL_SUCCEEDED (rc))
{
ODBC_Errors ("SQLGetDescField");
goto endCursor;
}
if (len)
printf ("^^<%.*s>", (int) len, buf);
}
if (colNum < numCols)
putchar (' ');
}
}
printf (" .\n");
totalRows++;
}
printf ("\n\nStatement returned %lu rows.\n", totalRows);
totalSets++;
}
while (SQLMoreResults (hstmt) == SQL_SUCCESS);
endCursor:
SQLCloseCursor (hstmt);
return 0;
}
int
ODBC_Execute (char *qr)
{
int rc;
SQLCHAR *Statement = (SQLCHAR *) qr;
if ((rc = SQLExecDirect (hstmt, Statement, SQL_NTS)) != SQL_SUCCESS)
{
ODBC_Errors ("ODBC_Execute");
if (rc != SQL_SUCCESS_WITH_INFO)
return -1;
}
return 0;
}
char dsn[] = "Local Virtuoso";
char uid[] = "dba";
char pwd[] = "dba";
char txt[] = "sparql SELECT * WHERE {?s ?p ?o} LIMIT 50";
int
main (int argc, char *argv[])
{
if (ODBC_Connect (dsn, uid, pwd))
exit (1);
if (ODBC_Execute (txt) == 0)
ODBC_PrintResult ();
ODBC_Disconnect ();
exit (0);
}
]]></programlisting>
<tip><title>See Also:</title>
<itemizedlist mark="bullet">
<listitem><link linkend="rdfandsparql">RDF Data Access and Data Management</link></listitem>
</itemizedlist>
</tip>
</sect4>
</sect3>
</sect2>
</sect1>
|