adodb-ado.inc.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. <?php
  2. /*
  3. @version v5.20.17 31-Mar-2020
  4. @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  5. @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community
  6. Released under both BSD license and Lesser GPL library license.
  7. Whenever there is any discrepancy between the two licenses,
  8. the BSD license will take precedence.
  9. Set tabs to 4 for best viewing.
  10. Latest version is available at http://adodb.org/
  11. Microsoft ADO data driver. Requires ADO. Works only on MS Windows.
  12. */
  13. // security - hide paths
  14. if (!defined('ADODB_DIR')) die();
  15. define("_ADODB_ADO_LAYER", 1 );
  16. /*--------------------------------------------------------------------------------------
  17. --------------------------------------------------------------------------------------*/
  18. class ADODB_ado extends ADOConnection {
  19. var $databaseType = "ado";
  20. var $_bindInputArray = false;
  21. var $fmtDate = "'Y-m-d'";
  22. var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
  23. var $replaceQuote = "''"; // string to use to replace quotes
  24. var $dataProvider = "ado";
  25. var $hasAffectedRows = true;
  26. var $adoParameterType = 201; // 201 = long varchar, 203=long wide varchar, 205 = long varbinary
  27. var $_affectedRows = false;
  28. var $_thisTransactions;
  29. var $_cursor_type = 3; // 3=adOpenStatic,0=adOpenForwardOnly,1=adOpenKeyset,2=adOpenDynamic
  30. var $_cursor_location = 3; // 2=adUseServer, 3 = adUseClient;
  31. var $_lock_type = -1;
  32. var $_execute_option = -1;
  33. var $poorAffectedRows = true;
  34. var $charPage;
  35. function __construct()
  36. {
  37. $this->_affectedRows = new VARIANT;
  38. }
  39. function ServerInfo()
  40. {
  41. if (!empty($this->_connectionID)) $desc = $this->_connectionID->provider;
  42. return array('description' => $desc, 'version' => '');
  43. }
  44. function _affectedrows()
  45. {
  46. if (PHP_VERSION >= 5) return $this->_affectedRows;
  47. return $this->_affectedRows->value;
  48. }
  49. // you can also pass a connection string like this:
  50. //
  51. // $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB');
  52. function _connect($argHostname, $argUsername, $argPassword, $argProvider= 'MSDASQL')
  53. {
  54. $u = 'UID';
  55. $p = 'PWD';
  56. if (!empty($this->charPage))
  57. $dbc = new COM('ADODB.Connection',null,$this->charPage);
  58. else
  59. $dbc = new COM('ADODB.Connection');
  60. if (! $dbc) return false;
  61. /* special support if provider is mssql or access */
  62. if ($argProvider=='mssql') {
  63. $u = 'User Id'; //User parameter name for OLEDB
  64. $p = 'Password';
  65. $argProvider = "SQLOLEDB"; // SQL Server Provider
  66. // not yet
  67. //if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename";
  68. //use trusted conection for SQL if username not specified
  69. if (!$argUsername) $argHostname .= ";Trusted_Connection=Yes";
  70. } else if ($argProvider=='access')
  71. $argProvider = "Microsoft.Jet.OLEDB.4.0"; // Microsoft Jet Provider
  72. if ($argProvider) $dbc->Provider = $argProvider;
  73. if ($argUsername) $argHostname .= ";$u=$argUsername";
  74. if ($argPassword)$argHostname .= ";$p=$argPassword";
  75. if ($this->debug) ADOConnection::outp( "Host=".$argHostname."<BR>\n version=$dbc->version");
  76. // @ added below for php 4.0.1 and earlier
  77. @$dbc->Open((string) $argHostname);
  78. $this->_connectionID = $dbc;
  79. $dbc->CursorLocation = $this->_cursor_location;
  80. return $dbc->State > 0;
  81. }
  82. // returns true or false
  83. function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL')
  84. {
  85. return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider);
  86. }
  87. /*
  88. adSchemaCatalogs = 1,
  89. adSchemaCharacterSets = 2,
  90. adSchemaCollations = 3,
  91. adSchemaColumns = 4,
  92. adSchemaCheckConstraints = 5,
  93. adSchemaConstraintColumnUsage = 6,
  94. adSchemaConstraintTableUsage = 7,
  95. adSchemaKeyColumnUsage = 8,
  96. adSchemaReferentialContraints = 9,
  97. adSchemaTableConstraints = 10,
  98. adSchemaColumnsDomainUsage = 11,
  99. adSchemaIndexes = 12,
  100. adSchemaColumnPrivileges = 13,
  101. adSchemaTablePrivileges = 14,
  102. adSchemaUsagePrivileges = 15,
  103. adSchemaProcedures = 16,
  104. adSchemaSchemata = 17,
  105. adSchemaSQLLanguages = 18,
  106. adSchemaStatistics = 19,
  107. adSchemaTables = 20,
  108. adSchemaTranslations = 21,
  109. adSchemaProviderTypes = 22,
  110. adSchemaViews = 23,
  111. adSchemaViewColumnUsage = 24,
  112. adSchemaViewTableUsage = 25,
  113. adSchemaProcedureParameters = 26,
  114. adSchemaForeignKeys = 27,
  115. adSchemaPrimaryKeys = 28,
  116. adSchemaProcedureColumns = 29,
  117. adSchemaDBInfoKeywords = 30,
  118. adSchemaDBInfoLiterals = 31,
  119. adSchemaCubes = 32,
  120. adSchemaDimensions = 33,
  121. adSchemaHierarchies = 34,
  122. adSchemaLevels = 35,
  123. adSchemaMeasures = 36,
  124. adSchemaProperties = 37,
  125. adSchemaMembers = 38
  126. */
  127. function MetaTables($ttype = false, $showSchema = false, $mask = false)
  128. {
  129. $arr= array();
  130. $dbc = $this->_connectionID;
  131. $adors=@$dbc->OpenSchema(20);//tables
  132. if ($adors){
  133. $f = $adors->Fields(2);//table/view name
  134. $t = $adors->Fields(3);//table type
  135. while (!$adors->EOF){
  136. $tt=substr($t->value,0,6);
  137. if ($tt!='SYSTEM' && $tt !='ACCESS')
  138. $arr[]=$f->value;
  139. //print $f->value . ' ' . $t->value.'<br>';
  140. $adors->MoveNext();
  141. }
  142. $adors->Close();
  143. }
  144. return $arr;
  145. }
  146. function MetaColumns($table, $normalize=true)
  147. {
  148. $table = strtoupper($table);
  149. $arr = array();
  150. $dbc = $this->_connectionID;
  151. $adors=@$dbc->OpenSchema(4);//tables
  152. if ($adors){
  153. $t = $adors->Fields(2);//table/view name
  154. while (!$adors->EOF){
  155. if (strtoupper($t->Value) == $table) {
  156. $fld = new ADOFieldObject();
  157. $c = $adors->Fields(3);
  158. $fld->name = $c->Value;
  159. $fld->type = 'CHAR'; // cannot discover type in ADO!
  160. $fld->max_length = -1;
  161. $arr[strtoupper($fld->name)]=$fld;
  162. }
  163. $adors->MoveNext();
  164. }
  165. $adors->Close();
  166. }
  167. $false = false;
  168. return empty($arr) ? $false : $arr;
  169. }
  170. /* returns queryID or false */
  171. function _query($sql,$inputarr=false)
  172. {
  173. $dbc = $this->_connectionID;
  174. $false = false;
  175. // return rs
  176. if ($inputarr) {
  177. if (!empty($this->charPage))
  178. $oCmd = new COM('ADODB.Command',null,$this->charPage);
  179. else
  180. $oCmd = new COM('ADODB.Command');
  181. $oCmd->ActiveConnection = $dbc;
  182. $oCmd->CommandText = $sql;
  183. $oCmd->CommandType = 1;
  184. // Map by http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ado270/htm/mdmthcreateparam.asp
  185. // Check issue http://bugs.php.net/bug.php?id=40664 !!!
  186. foreach ($inputarr as $val) {
  187. $type = gettype($val);
  188. $len=strlen($val);
  189. if ($type == 'boolean')
  190. $this->adoParameterType = 11;
  191. else if ($type == 'integer')
  192. $this->adoParameterType = 3;
  193. else if ($type == 'double')
  194. $this->adoParameterType = 5;
  195. elseif ($type == 'string')
  196. $this->adoParameterType = 202;
  197. else if (($val === null) || (!defined($val)))
  198. $len=1;
  199. else
  200. $this->adoParameterType = 130;
  201. // name, type, direction 1 = input, len,
  202. $p = $oCmd->CreateParameter('name',$this->adoParameterType,1,$len,$val);
  203. $oCmd->Parameters->Append($p);
  204. }
  205. $p = false;
  206. $rs = $oCmd->Execute();
  207. $e = $dbc->Errors;
  208. if ($dbc->Errors->Count > 0) return $false;
  209. return $rs;
  210. }
  211. $rs = @$dbc->Execute($sql,$this->_affectedRows, $this->_execute_option);
  212. if ($dbc->Errors->Count > 0) return $false;
  213. if (! $rs) return $false;
  214. if ($rs->State == 0) {
  215. $true = true;
  216. return $true; // 0 = adStateClosed means no records returned
  217. }
  218. return $rs;
  219. }
  220. function BeginTrans()
  221. {
  222. if ($this->transOff) return true;
  223. if (isset($this->_thisTransactions))
  224. if (!$this->_thisTransactions) return false;
  225. else {
  226. $o = $this->_connectionID->Properties("Transaction DDL");
  227. $this->_thisTransactions = $o ? true : false;
  228. if (!$o) return false;
  229. }
  230. @$this->_connectionID->BeginTrans();
  231. $this->transCnt += 1;
  232. return true;
  233. }
  234. function CommitTrans($ok=true)
  235. {
  236. if (!$ok) return $this->RollbackTrans();
  237. if ($this->transOff) return true;
  238. @$this->_connectionID->CommitTrans();
  239. if ($this->transCnt) @$this->transCnt -= 1;
  240. return true;
  241. }
  242. function RollbackTrans() {
  243. if ($this->transOff) return true;
  244. @$this->_connectionID->RollbackTrans();
  245. if ($this->transCnt) @$this->transCnt -= 1;
  246. return true;
  247. }
  248. /* Returns: the last error message from previous database operation */
  249. function ErrorMsg()
  250. {
  251. if (!$this->_connectionID) return "No connection established";
  252. $errc = $this->_connectionID->Errors;
  253. if (!$errc) return "No Errors object found";
  254. if ($errc->Count == 0) return '';
  255. $err = $errc->Item($errc->Count-1);
  256. return $err->Description;
  257. }
  258. function ErrorNo()
  259. {
  260. $errc = $this->_connectionID->Errors;
  261. if ($errc->Count == 0) return 0;
  262. $err = $errc->Item($errc->Count-1);
  263. return $err->NativeError;
  264. }
  265. // returns true or false
  266. function _close()
  267. {
  268. if ($this->_connectionID) $this->_connectionID->Close();
  269. $this->_connectionID = false;
  270. return true;
  271. }
  272. }
  273. /*--------------------------------------------------------------------------------------
  274. Class Name: Recordset
  275. --------------------------------------------------------------------------------------*/
  276. class ADORecordSet_ado extends ADORecordSet {
  277. var $bind = false;
  278. var $databaseType = "ado";
  279. var $dataProvider = "ado";
  280. var $_tarr = false; // caches the types
  281. var $_flds; // and field objects
  282. var $canSeek = true;
  283. var $hideErrors = true;
  284. function __construct($id,$mode=false)
  285. {
  286. if ($mode === false) {
  287. global $ADODB_FETCH_MODE;
  288. $mode = $ADODB_FETCH_MODE;
  289. }
  290. $this->fetchMode = $mode;
  291. return parent::__construct($id,$mode);
  292. }
  293. // returns the field object
  294. function FetchField($fieldOffset = -1) {
  295. $off=$fieldOffset+1; // offsets begin at 1
  296. $o= new ADOFieldObject();
  297. $rs = $this->_queryID;
  298. $f = $rs->Fields($fieldOffset);
  299. $o->name = $f->Name;
  300. $t = $f->Type;
  301. $o->type = $this->MetaType($t);
  302. $o->max_length = $f->DefinedSize;
  303. $o->ado_type = $t;
  304. //print "off=$off name=$o->name type=$o->type len=$o->max_length<br>";
  305. return $o;
  306. }
  307. /* Use associative array to get fields array */
  308. function Fields($colname)
  309. {
  310. if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];
  311. if (!$this->bind) {
  312. $this->bind = array();
  313. for ($i=0; $i < $this->_numOfFields; $i++) {
  314. $o = $this->FetchField($i);
  315. $this->bind[strtoupper($o->name)] = $i;
  316. }
  317. }
  318. return $this->fields[$this->bind[strtoupper($colname)]];
  319. }
  320. function _initrs()
  321. {
  322. $rs = $this->_queryID;
  323. $this->_numOfRows = $rs->RecordCount;
  324. $f = $rs->Fields;
  325. $this->_numOfFields = $f->Count;
  326. }
  327. // should only be used to move forward as we normally use forward-only cursors
  328. function _seek($row)
  329. {
  330. $rs = $this->_queryID;
  331. // absoluteposition doesn't work -- my maths is wrong ?
  332. // $rs->AbsolutePosition->$row-2;
  333. // return true;
  334. if ($this->_currentRow > $row) return false;
  335. @$rs->Move((integer)$row - $this->_currentRow-1); //adBookmarkFirst
  336. return true;
  337. }
  338. /*
  339. OLEDB types
  340. enum DBTYPEENUM
  341. { DBTYPE_EMPTY = 0,
  342. DBTYPE_NULL = 1,
  343. DBTYPE_I2 = 2,
  344. DBTYPE_I4 = 3,
  345. DBTYPE_R4 = 4,
  346. DBTYPE_R8 = 5,
  347. DBTYPE_CY = 6,
  348. DBTYPE_DATE = 7,
  349. DBTYPE_BSTR = 8,
  350. DBTYPE_IDISPATCH = 9,
  351. DBTYPE_ERROR = 10,
  352. DBTYPE_BOOL = 11,
  353. DBTYPE_VARIANT = 12,
  354. DBTYPE_IUNKNOWN = 13,
  355. DBTYPE_DECIMAL = 14,
  356. DBTYPE_UI1 = 17,
  357. DBTYPE_ARRAY = 0x2000,
  358. DBTYPE_BYREF = 0x4000,
  359. DBTYPE_I1 = 16,
  360. DBTYPE_UI2 = 18,
  361. DBTYPE_UI4 = 19,
  362. DBTYPE_I8 = 20,
  363. DBTYPE_UI8 = 21,
  364. DBTYPE_GUID = 72,
  365. DBTYPE_VECTOR = 0x1000,
  366. DBTYPE_RESERVED = 0x8000,
  367. DBTYPE_BYTES = 128,
  368. DBTYPE_STR = 129,
  369. DBTYPE_WSTR = 130,
  370. DBTYPE_NUMERIC = 131,
  371. DBTYPE_UDT = 132,
  372. DBTYPE_DBDATE = 133,
  373. DBTYPE_DBTIME = 134,
  374. DBTYPE_DBTIMESTAMP = 135
  375. ADO Types
  376. adEmpty = 0,
  377. adTinyInt = 16,
  378. adSmallInt = 2,
  379. adInteger = 3,
  380. adBigInt = 20,
  381. adUnsignedTinyInt = 17,
  382. adUnsignedSmallInt = 18,
  383. adUnsignedInt = 19,
  384. adUnsignedBigInt = 21,
  385. adSingle = 4,
  386. adDouble = 5,
  387. adCurrency = 6,
  388. adDecimal = 14,
  389. adNumeric = 131,
  390. adBoolean = 11,
  391. adError = 10,
  392. adUserDefined = 132,
  393. adVariant = 12,
  394. adIDispatch = 9,
  395. adIUnknown = 13,
  396. adGUID = 72,
  397. adDate = 7,
  398. adDBDate = 133,
  399. adDBTime = 134,
  400. adDBTimeStamp = 135,
  401. adBSTR = 8,
  402. adChar = 129,
  403. adVarChar = 200,
  404. adLongVarChar = 201,
  405. adWChar = 130,
  406. adVarWChar = 202,
  407. adLongVarWChar = 203,
  408. adBinary = 128,
  409. adVarBinary = 204,
  410. adLongVarBinary = 205,
  411. adChapter = 136,
  412. adFileTime = 64,
  413. adDBFileTime = 137,
  414. adPropVariant = 138,
  415. adVarNumeric = 139
  416. */
  417. function MetaType($t,$len=-1,$fieldobj=false)
  418. {
  419. if (is_object($t)) {
  420. $fieldobj = $t;
  421. $t = $fieldobj->type;
  422. $len = $fieldobj->max_length;
  423. }
  424. if (!is_numeric($t)) return $t;
  425. switch ($t) {
  426. case 0:
  427. case 12: // variant
  428. case 8: // bstr
  429. case 129: //char
  430. case 130: //wc
  431. case 200: // varc
  432. case 202:// varWC
  433. case 128: // bin
  434. case 204: // varBin
  435. case 72: // guid
  436. if ($len <= $this->blobSize) return 'C';
  437. case 201:
  438. case 203:
  439. return 'X';
  440. case 128:
  441. case 204:
  442. case 205:
  443. return 'B';
  444. case 7:
  445. case 133: return 'D';
  446. case 134:
  447. case 135: return 'T';
  448. case 11: return 'L';
  449. case 16:// adTinyInt = 16,
  450. case 2://adSmallInt = 2,
  451. case 3://adInteger = 3,
  452. case 4://adBigInt = 20,
  453. case 17://adUnsignedTinyInt = 17,
  454. case 18://adUnsignedSmallInt = 18,
  455. case 19://adUnsignedInt = 19,
  456. case 20://adUnsignedBigInt = 21,
  457. return 'I';
  458. default: return 'N';
  459. }
  460. }
  461. // time stamp not supported yet
  462. function _fetch()
  463. {
  464. $rs = $this->_queryID;
  465. if (!$rs or $rs->EOF) {
  466. $this->fields = false;
  467. return false;
  468. }
  469. $this->fields = array();
  470. if (!$this->_tarr) {
  471. $tarr = array();
  472. $flds = array();
  473. for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
  474. $f = $rs->Fields($i);
  475. $flds[] = $f;
  476. $tarr[] = $f->Type;
  477. }
  478. // bind types and flds only once
  479. $this->_tarr = $tarr;
  480. $this->_flds = $flds;
  481. }
  482. $t = reset($this->_tarr);
  483. $f = reset($this->_flds);
  484. if ($this->hideErrors) $olde = error_reporting(E_ERROR|E_CORE_ERROR);// sometimes $f->value be null
  485. for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
  486. //echo "<p>",$t,' ';var_dump($f->value); echo '</p>';
  487. switch($t) {
  488. case 135: // timestamp
  489. if (!strlen((string)$f->value)) $this->fields[] = false;
  490. else {
  491. if (!is_numeric($f->value)) # $val = variant_date_to_timestamp($f->value);
  492. // VT_DATE stores dates as (float) fractional days since 1899/12/30 00:00:00
  493. $val=(float) variant_cast($f->value,VT_R8)*3600*24-2209161600;
  494. else
  495. $val = $f->value;
  496. $this->fields[] = adodb_date('Y-m-d H:i:s',$val);
  497. }
  498. break;
  499. case 133:// A date value (yyyymmdd)
  500. if ($val = $f->value) {
  501. $this->fields[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2);
  502. } else
  503. $this->fields[] = false;
  504. break;
  505. case 7: // adDate
  506. if (!strlen((string)$f->value)) $this->fields[] = false;
  507. else {
  508. if (!is_numeric($f->value)) $val = variant_date_to_timestamp($f->value);
  509. else $val = $f->value;
  510. if (($val % 86400) == 0) $this->fields[] = adodb_date('Y-m-d',$val);
  511. else $this->fields[] = adodb_date('Y-m-d H:i:s',$val);
  512. }
  513. break;
  514. case 1: // null
  515. $this->fields[] = false;
  516. break;
  517. case 6: // currency is not supported properly;
  518. ADOConnection::outp( '<b>'.$f->Name.': currency type not supported by PHP</b>');
  519. $this->fields[] = (float) $f->value;
  520. break;
  521. case 11: //BIT;
  522. $val = "";
  523. if(is_bool($f->value)) {
  524. if($f->value==true) $val = 1;
  525. else $val = 0;
  526. }
  527. if(is_null($f->value)) $val = null;
  528. $this->fields[] = $val;
  529. break;
  530. default:
  531. $this->fields[] = $f->value;
  532. break;
  533. }
  534. //print " $f->value $t, ";
  535. $f = next($this->_flds);
  536. $t = next($this->_tarr);
  537. } // for
  538. if ($this->hideErrors) error_reporting($olde);
  539. @$rs->MoveNext(); // @ needed for some versions of PHP!
  540. if ($this->fetchMode & ADODB_FETCH_ASSOC) {
  541. $this->fields = $this->GetRowAssoc();
  542. }
  543. return true;
  544. }
  545. function NextRecordSet()
  546. {
  547. $rs = $this->_queryID;
  548. $this->_queryID = $rs->NextRecordSet();
  549. //$this->_queryID = $this->_QueryId->NextRecordSet();
  550. if ($this->_queryID == null) return false;
  551. $this->_currentRow = -1;
  552. $this->_currentPage = -1;
  553. $this->bind = false;
  554. $this->fields = false;
  555. $this->_flds = false;
  556. $this->_tarr = false;
  557. $this->_inited = false;
  558. $this->Init();
  559. return true;
  560. }
  561. function _close() {
  562. $this->_flds = false;
  563. @$this->_queryID->Close();// by Pete Dishman (peterd@telephonetics.co.uk)
  564. $this->_queryID = false;
  565. }
  566. }