PageRenderTime 54ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/ser-0.9.6/serweb-0.9.4/phplib/db_oracle.inc

#
PHP | 433 lines | 283 code | 50 blank | 100 comment | 62 complexity | 5268f18426e399dc60dfc77cc56e9406 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0
  1. <?php
  2. /*
  3. * Oracle accessor based on Session Management for PHP3
  4. *
  5. * Copyright (c) 1998-2000 Luis Francisco Gonzalez Hernandez
  6. *
  7. * $Id: db_oracle.inc,v 1.2 2004/08/09 12:59:35 kozlik Exp $
  8. *
  9. */
  10. class DB_Sql {
  11. var $Debug = false;
  12. var $Home = "/u01/app/oracle/product/8.0.4";
  13. var $Remote = 1;
  14. /* Due to a strange error with Oracle 8.0.5, Apache and PHP3.0.6
  15. you don't need to set the ENV - on my system Apache
  16. will change to a zombie, if I don't set this to FALSE!
  17. If unsure try it out, if it works. */
  18. var $OraPutEnv = true;
  19. var $Database = "";
  20. var $User = "";
  21. var $Password = "";
  22. var $Link_ID = 0;
  23. var $Query_ID = 0;
  24. var $Record = array();
  25. var $Row;
  26. var $Errno = 0;
  27. var $Error = "";
  28. var $ora_no_next_fetch=false;
  29. /* copied from db_mysql for completeness */
  30. /* public: identification constant. never change this. */
  31. var $type = "oracle";
  32. var $revision = "1.2";
  33. var $Halt_On_Error = "yes"; ## "yes" (halt with message), "no" (ignore errors quietly), "report" (ignore errror, but spit a warning)
  34. /* public: constructor */
  35. function DB_Sql($query = "") {
  36. $this->query($query);
  37. }
  38. /* public: some trivial reporting */
  39. function link_id() {
  40. return $this->Link_ID;
  41. }
  42. function query_id() {
  43. return $this->Query_ID;
  44. }
  45. function connect() {
  46. ## see above why we do this
  47. if ($this->OraPutEnv) {
  48. PutEnv("ORACLE_SID=$this->Database");
  49. PutEnv("ORACLE_HOME=$this->Home");
  50. }
  51. if ( 0 == $this->Link_ID ) {
  52. if($this->Debug) {
  53. printf("<br>Connect()ing to $this->Database...<br>\n");
  54. }
  55. if($this->Remote) {
  56. if($this->Debug) {
  57. printf("<br>connect() $this->User/******@$this->Database.world<br>\n");
  58. }
  59. $this->Link_ID=ora_plogon
  60. ("$this->User/$this->Password@$this->Database","");
  61. /************** (comment by SSilk)
  62. this dosn't work on my system:
  63. $this->Link_ID=ora_plogon
  64. ("$this->User@$this->Database.world","$this->Password");
  65. ***************/
  66. } else {
  67. if($this->Debug) {
  68. printf("<br>connect() $this->User, $this->Password <br>\n");
  69. }
  70. $this->Link_ID=ora_plogon("$this->User","$this->Password");
  71. /* (comment by SSilk: don't know how this could work, but I leave this untouched!) */
  72. }
  73. if($this->Debug) {
  74. printf("<br>connect() Link_ID: $this->Link_ID<br>\n");
  75. }
  76. if (!$this->Link_ID) {
  77. $this->halt("connect() Link-ID == false " .
  78. "($this->Link_ID), ora_plogon failed");
  79. } else {
  80. //echo "commit on<p>";
  81. ora_commiton($this->Link_ID);
  82. }
  83. if($this->Debug) {
  84. printf("<br>connect() Obtained the Link_ID: $this->Link_ID<br>\n");
  85. }
  86. }
  87. }
  88. ## In order to increase the # of cursors per system/user go edit the
  89. ## init.ora file and increase the max_open_cursors parameter. Yours is on
  90. ## the default value, 100 per user.
  91. ## We tried to change the behaviour of query() in a way, that it tries
  92. ## to safe cursors, but on the other side be carefull with this, that you
  93. ## don't use an old result.
  94. ##
  95. ## You can also make extensive use of ->disconnect()!
  96. ## The unused QueryIDs will be recycled sometimes.
  97. function query($Query_String) {
  98. /* No empty queries, please, since PHP4 chokes on them. */
  99. if ($Query_String == "")
  100. /* The empty query string is passed on from the constructor,
  101. * when calling the class without a query, e.g. in situations
  102. * like these: '$db = new DB_Sql_Subclass;'
  103. */
  104. return 0;
  105. $this->connect();
  106. $this->lastQuery=$Query_String;
  107. if (!$this->Query_ID) {
  108. $this->Query_ID= ora_open($this->Link_ID);
  109. }
  110. if($this->Debug) {
  111. printf("Debug: query = %s<br>\n", $Query_String);
  112. printf("<br>Debug: Query_ID: %d<br>\n", $this->Query_ID);
  113. }
  114. if(!@ora_parse($this->Query_ID,$Query_String)) {
  115. $this->Errno=ora_errorcode($this->Query_ID);
  116. $this->Error=ora_error($this->Query_ID);
  117. $this->halt("<BR>ora_parse() failed:<BR>$Query_String<BR><small>Snap & paste this to sqlplus!</SMALL>");
  118. } elseif (!@ora_exec($this->Query_ID)) {
  119. $this->Errno=ora_errorcode($this->Query_ID);
  120. $this->Error=ora_error($this->Query_ID);
  121. $this->halt("<BR>\n$Query_String\n<BR><small>Snap & paste this to sqlplus!</SMALL>");
  122. }
  123. $this->Row=0;
  124. if(!$this->Query_ID) {
  125. $this->halt("Invalid SQL: ".$Query_String);
  126. }
  127. return $this->Query_ID;
  128. }
  129. function next_record() {
  130. if (!$this->no_next_fetch &&
  131. 0 == ora_fetch($this->Query_ID)) {
  132. if ($this->Debug) {
  133. printf("<br>next_record(): ID: %d,Rows: %d<br>\n",
  134. $this->Query_ID,$this->num_rows());
  135. }
  136. $this->Row +=1;
  137. $errno=ora_errorcode($this->Query_ID);
  138. if(1403 == $errno) { # 1043 means no more records found
  139. $this->Errno=0;
  140. $this->Error="";
  141. $this->disconnect();
  142. $stat=0;
  143. } else {
  144. $this->Error=ora_error($this->Query_ID);
  145. $this->Errno=$errno;
  146. if($this->Debug) {
  147. printf("<br>%d Error: %s",
  148. $this->Errno,
  149. $this->Error);
  150. }
  151. $stat=0;
  152. }
  153. } else {
  154. $this->no_next_fetch=false;
  155. for($ix=0;$ix<ora_numcols($this->Query_ID);$ix++) {
  156. $col=strtolower(ora_columnname($this->Query_ID,$ix));
  157. $value=ora_getcolumn($this->Query_ID,$ix);
  158. $this->Record[ "$col" ] = $value;
  159. # echo"<b>[$col]</b>: $value <br>\n";
  160. }
  161. $stat=1;
  162. }
  163. return $stat;
  164. }
  165. ## seek() works only for $pos - 1 and $pos
  166. ## Perhaps I make a own implementation, but my
  167. ## opinion is, that this should be done by PHP3
  168. function seek($pos) {
  169. if ($this->Row - 1 == $pos) {
  170. $this->no_next_fetch=true;
  171. } elseif ($this->Row == $pos ) {
  172. ## do nothing
  173. } else {
  174. $this->halt("Invalid seek(): Position is cannot be handled by API.<BR>".
  175. "Difference too big. Wanted: $pos Current pos: $this->Row");
  176. }
  177. if ($Debug) echo "<BR>Debug: seek = $pos<BR>";
  178. $this->Row=$pos;
  179. }
  180. function lock($table, $mode = "write") {
  181. if ($mode == "write") {
  182. $result = ora_do($this->Link_ID, "lock table $table in row exclusive mode");
  183. } else {
  184. $result = 1;
  185. }
  186. return $result;
  187. }
  188. function unlock() {
  189. return ora_do($this->Link_ID, "commit");
  190. }
  191. function metadata($table,$full=false) {
  192. $count = 0;
  193. $id = 0;
  194. $res = array();
  195. /*
  196. * Due to compatibility problems with Table we changed the behavior
  197. * of metadata();
  198. * depending on $full, metadata returns the following values:
  199. *
  200. * - full is false (default):
  201. * $result[]:
  202. * [0]["table"] table name
  203. * [0]["name"] field name
  204. * [0]["type"] field type
  205. * [0]["len"] field length
  206. * [0]["flags"] field flags ("NOT NULL", "INDEX")
  207. * [0]["format"] precision and scale of number (eg. "10,2") or empty
  208. * [0]["index"] name of index (if has one)
  209. * [0]["chars"] number of chars (if any char-type)
  210. *
  211. * - full is true
  212. * $result[]:
  213. * ["num_fields"] number of metadata records
  214. * [0]["table"] table name
  215. * [0]["name"] field name
  216. * [0]["type"] field type
  217. * [0]["len"] field length
  218. * [0]["flags"] field flags ("NOT NULL", "INDEX")
  219. * [0]["format"] precision and scale of number (eg. "10,2") or empty
  220. * [0]["index"] name of index (if has one)
  221. * [0]["chars"] number of chars (if any char-type)
  222. * ["meta"][field name] index of field named "field name"
  223. * The last one is used, if you have a field name, but no index.
  224. * Test: if (isset($result['meta']['myfield'])) {} ...
  225. */
  226. $this->connect();
  227. ## This is a RIGHT OUTER JOIN: "(+)", if you want to see, what
  228. ## this query results try the following:
  229. ## $table = new Table; $db = new my_DB_Sql; # you have to make
  230. ## # your own class
  231. ## $table->show_results($db->query(see query vvvvvv))
  232. ##
  233. $this->query("SELECT T.table_name,T.column_name,T.data_type,".
  234. "T.data_length,T.data_precision,T.data_scale,T.nullable,".
  235. "T.char_col_decl_length,I.index_name".
  236. " FROM ALL_TAB_COLUMNS T,ALL_IND_COLUMNS I".
  237. " WHERE T.column_name=I.column_name (+)".
  238. " AND T.table_name=I.table_name (+)".
  239. " AND T.table_name=UPPER('$table') ORDER BY T.column_id");
  240. $i=0;
  241. while ($this->next_record()) {
  242. $res[$i]["table"] = $this->Record[table_name];
  243. $res[$i]["name"] = strtolower($this->Record[column_name]);
  244. $res[$i]["type"] = $this->Record[data_type];
  245. $res[$i]["len"] = $this->Record[data_length];
  246. if ($this->Record[index_name]) $res[$i]["flags"] = "INDEX ";
  247. $res[$i]["flags"] .= ( $this->Record[nullable] == 'N') ? '' : 'NOT NULL';
  248. $res[$i]["format"]= (int)$this->Record[data_precision].",".
  249. (int)$this->Record[data_scale];
  250. if ("0,0"==$res[$i]["format"]) $res[$i]["format"]='';
  251. $res[$i]["index"] = $this->Record[index_name];
  252. $res[$i]["chars"] = $this->Record[char_col_decl_length];
  253. if ($full) {
  254. $j=$res[$i]["name"];
  255. $res["meta"][$j] = $i;
  256. $res["meta"][strtoupper($j)] = $i;
  257. }
  258. if ($full) $res["meta"][$res[$i]["name"]] = $i;
  259. $i++;
  260. }
  261. if ($full) $res["num_fields"]=$i;
  262. # $this->disconnect();
  263. return $res;
  264. }
  265. ## THIS FUNCTION IS UNSTESTED!
  266. function affected_rows() {
  267. if ($Debug) echo "<BR>Debug: affected_rows=". ora_numrows($this->Query_ID)."<BR>";
  268. return ora_numrows($this->Query_ID);
  269. }
  270. ## Known bugs: It will not work for SELECT DISTINCT and any
  271. ## other constructs which are depending on the resulting rows.
  272. ## So you *really need* to check every query you make, if it
  273. ## will work with it.
  274. ##
  275. ## Also, for a qualified replacement you need to parse the
  276. ## selection, cause this will fail: "SELECT id, from FROM ...").
  277. ## "FROM" is - as far as I know a keyword in Oracle, so it can
  278. ## only be used in this way. But you have been warned.
  279. function num_rows() {
  280. $curs=ora_open($this->Link_ID);
  281. ## this is the important part and it is also the HACK!
  282. if (eregi("^[[:space:]]*SELECT[[:space:]]",$this->lastQuery) ) {
  283. $from_pos = strpos(strtoupper($this->lastQuery),"FROM");
  284. $q = "SELECT count(*) ". substr($this->lastQuery, $from_pos);
  285. ORA_parse($curs,$q);
  286. ORA_exec($curs);
  287. ORA_fetch($curs);
  288. if ($Debug) echo "<BR>Debug: num_rows=". ORA_getcolumn($curs,0)."<BR>";
  289. return(ORA_getcolumn($curs,0));
  290. } else {
  291. $this->halt("Last Query was not a SELECT: $this->lastQuery");
  292. }
  293. }
  294. function num_fields() {
  295. if ($Debug) echo "<BR>Debug: num_fields=". ora_numcols($this->Query_ID) . "<BR>";
  296. return ora_numcols($this->Query_ID);
  297. }
  298. function nf() {
  299. return $this->num_rows();
  300. }
  301. function np() {
  302. print $this->num_rows();
  303. }
  304. function f($Name) {
  305. return $this->Record[$Name];
  306. }
  307. function p($Name) {
  308. print $this->Record[$Name];
  309. }
  310. /* public: sequence number */
  311. function nextid($seq_name)
  312. {
  313. $this->connect();
  314. /* Independent Query_ID */
  315. $Query_ID = ora_open($this->Link_ID);
  316. if(!@ora_parse($Query_ID,"SELECT $seq_name.NEXTVAL FROM DUAL"))
  317. {
  318. // There is no such sequence yet, then create it
  319. if(!@ora_parse($Query_ID,"CREATE SEQUENCE $seq_name")
  320. ||
  321. !@ora_exec($Query_ID)
  322. )
  323. {
  324. $this->halt("<BR> nextid() function - unable to create sequence");
  325. return 0;
  326. }
  327. @ora_parse($Query_ID,"SELECT $seq_name.NEXTVAL FROM DUAL");
  328. }
  329. if (!@ora_exec($Query_ID)) {
  330. $this->halt("<BR>ora_exec() failed:<BR>nextID function");
  331. }
  332. if (@ora_fetch($Query_ID) ) {
  333. $next_id = ora_getcolumn($Query_ID, 0);
  334. }
  335. else {
  336. $next_id = 0;
  337. }
  338. if ( Query_ID > 0 ) {
  339. ora_close(Query_ID);
  340. }
  341. return $next_id;
  342. }
  343. function disconnect() {
  344. if($this->Debug) {
  345. echo "Debug: Disconnecting $this->Query_ID...<br>\n";
  346. }
  347. if ( $this->Query_ID < 1 ) {
  348. echo "<B>Warning</B>: disconnect(): Cannot free ID $this->Query_ID\n";
  349. # return();
  350. }
  351. ora_close($this->Query_ID);
  352. $this->Query_ID=0;
  353. }
  354. /* private: error handling */
  355. function halt($msg) {
  356. if ($this->Halt_On_Error == "no")
  357. return;
  358. $this->haltmsg($msg);
  359. if ($this->Halt_On_Error != "report")
  360. die("Session halted.");
  361. }
  362. function haltmsg($msg) {
  363. printf("</td></tr></table><b>Database error:</b> %s<br>\n", $msg);
  364. printf("<b>Oracle Error</b>: %s (%s)<br>\n",
  365. $this->Errno,
  366. $this->Error);
  367. }
  368. function table_names() {
  369. $this->connect();
  370. $this->query("
  371. SELECT table_name,tablespace_name
  372. FROM user_tables");
  373. $i=0;
  374. while ($this->next_record())
  375. {
  376. $info[$i]["table_name"] =$this->Record["table_name"];
  377. $info[$i]["tablespace_name"]=$this->Record["tablespace_name"];
  378. $i++;
  379. }
  380. return $info;
  381. }
  382. }
  383. ?>