<?vsp 
--  
--  $Id: xmla.vsp,v 1.6 2006/08/15 19:30:34 source Exp $
--  
--  This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
--  project.
--  
--  Copyright (C) 1998-2006 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
--  
--  

  declare resp, inp, outp varchar;
  declare url varchar;
  declare op, err, nfo, stmt, dsn varchar;
  declare schema_rowsets, prop, prop_type, prop_value, prop_selected, prop_list, bookmarks any;
  declare rest, rest_type, rest_value, rest_selected, rest_list, use_bookmark, use_rowcount any;
  declare i, l, i1, tip_no, idx, _cnt, _skip, n_row, bookmark int;
  declare sel, tip, uname, pwd, _dsn, direction varchar;

  url := get_keyword ('url' , params, 'http://localhost:' || server_http_port () || '/XMLA');
  --url := get_keyword ('url' , params, 'http://mitko/XMLA/msxisapi.dll');
  --dsn := get_keyword ('dsn' , params, 'Provider=MSOLAP;Data Source=local');
  dsn := get_keyword ('dsn' , params, '');
  uname := get_keyword ('uname' , params, '');
  pwd := get_keyword ('pwd' , params, '');
  tip_no := atoi(get_keyword ('tip_no' , params, '0'));
  _skip := get_keyword ('skip' , params, '0');
  n_row := get_keyword ('n_row' , params, '0');
  direction := get_keyword ('direction' , params, 'forward');
  bookmark := get_keyword ('bookmark' , params, '0');
  use_bookmark := get_keyword ('use_bookmark' , params, 'off');
  use_rowcount := get_keyword ('use_rowcount' , params, 'off');
  bookmarks := vector ();

  if ({?'add_dsn'} is not null)
    {
      http_rewrite ();
      http_request_status ('HTTP/1.1 302 Found');
      http_header ('Location: xmla_dsn_add.vsp\r\n');
    }

  if (get_keyword ('schema_rowsets', params) is not null)
    schema_rowsets := deserialize(decode_base64(get_keyword ('schema_rowsets', params)));
  else
    schema_rowsets := null;

  if (schema_rowsets is null and dsn = '')
    schema_rowsets := vector (N'DISCOVER_DATASOURCES');
  else if (length(schema_rowsets) = 1)
    schema_rowsets := vector (N'DISCOVER_DATASOURCES', N'DISCOVER_SCHEMA_ROWSETS', N'DISCOVER_PROPERTIES');

  if (get_keyword ('propt', params) is not null)
    {
      prop := deserialize(decode_base64(get_keyword ('propt', params)));
      prop_value := deserialize(decode_base64(get_keyword ('prop_value', params)));
      prop_type := deserialize(decode_base64(get_keyword ('prop_type', params)));
      prop_selected := deserialize(decode_base64(get_keyword ('prop_selected', params)));
    }
  else
    prop := prop_type := prop_value := prop_selected := vector ();

  if ({?'prop_set'} <> '')
    {
      declare ix int;
      ix := atoi ({?'prop_inx'});
      aset (prop_value, ix, {?'propv'});
      aset (prop_selected, ix, {?'props'});
    }
  l := length (prop_value); i := 0;
  if (dsn <> '')
    prop_list := vector (composite (), '', 'DataSourceInfo', dsn);
  else
    prop_list := vector (composite (), '');

  while (i < l)
    {
      if (prop_selected[i] = 'on')
        prop_list := vector_concat (prop_list, vector (prop[i], prop_value[i]));
      i := i + 1;
    }

  if (length (prop_list) < 3)
    prop_list := NULL;

  if (get_keyword ('restt', params) is not null)
    {
      rest := deserialize(decode_base64(get_keyword ('restt', params)));
      rest_value := deserialize(decode_base64(get_keyword ('rest_value', params)));
      rest_type := deserialize(decode_base64(get_keyword ('rest_type', params)));
      rest_selected := deserialize(decode_base64(get_keyword ('rest_selected', params)));
    }
  else
    rest := rest_type := rest_value := rest_selected := vector ();

  if ({?'rest_set'} <> '')
    {
      declare ix int;
      ix := atoi ({?'rest_inx'});
      aset (rest_value, ix, {?'restv'});
      aset (rest_selected, ix, {?'rests'});
    }

  l := length (rest_value); i := 0;
  rest_list := vector (composite (), '');

  while (i < l)
    {
      if (rest_selected[i] = 'on')
        rest_list := vector_concat (rest_list, vector (cast (rest[i] as varchar), rest_value[i]));
      i := i + 1;
    }

  if (length (rest_list) < 3)
    rest_list := NULL;

  op := {?'op'}; resp := null; err := '';

  {

  declare exit handler for sqlstate '*' {
    err := __SQL_MESSAGE;
    goto err;
  };

  if (isstring (op) and {?'exec'} is not null) op := atoi (op);

  nfo :=  get_keyword ('nfo' , params, 'DISCOVER_DATASOURCES');
  stmt :=  get_keyword ('stmt' , params, '[type a SQL statement here]');

  if (op = 1)
    {
       declare pos int;

       if (length (uname))
         {
	   pos := position ('UserName', prop_list);
	   if (pos > 0)
	     aset (prop_list, pos, uname);
	   else
	     prop_list := vector_concat (prop_list, vector ('UserName', uname));
         }

       if (length (pwd))
         {
	   pos := position ('Password', prop_list);
	   if (pos > 0)
	     aset (prop_list, pos, pwd);
	   else
	     prop_list := vector_concat (prop_list, vector ('Password', pwd));
         }

       resp := soap_client (url=>url,
		 operation=>'Discover',
		 target_namespace=>'urn:schemas-microsoft-com:xml-analysis',
		 soap_action=>'urn:schemas-microsoft-com:xml-analysis:Discover',
		 parameters=>
		    vector ('RequestType', nfo,
		            'Restrictions',
			          case when rest_list is not null then soap_box_structure ('RestrictionList',
				  rest_list) else null end,
			    'Properties',
			          case when prop_list is not null then soap_box_structure ('PropertyList',
				  prop_list) else null end
				  ),
		    --headers=>vector ('Session', xml_tree_doc (
		    --	  '<XA:Session'
		    --	  ||' xmlns:XA="urn:schemas-microsoft-com:xml-analysis"'
		    --	  ||' mustUnderstand="1" SessionID="???"/>'
		    --		 )),
		    style=>2);
       if (nfo = 'DISCOVER_DATASOURCES')
	 {
           tip_no := 1;
	 }
       else if (nfo = 'DISCOVER_SCHEMA_ROWSETS')
	 {
	   schema_rowsets := xpath_eval ('//SchemaName/text()', xml_tree_doc (resp[0]), 0);
	   declare _row any;
	   _row := xpath_eval ('//root/row/Restrictions/*', xml_tree_doc (resp[0]), 0);
	   rest := make_array (length(_row), 'any');
	   rest_value := make_array (length(_row), 'any');
	   rest_type := make_array (length(_row), 'any');
	   rest_selected := make_array (length(_row), 'any');

           i := 0; l := length (rest_value);
           while (i < l)
             {
	       aset (rest, i, xpath_eval ('local-name(/*)', xml_cut (_row[i]), 1));
	       aset (rest_value, i, '');
	       aset (rest_type, i, 'Write');
               i := i + 1;
	     }
	   if (length (schema_rowsets) < 1)
             schema_rowsets := vector (N'DISCOVER_DATASOURCES', N'DISCOVER_SCHEMA_ROWSETS', N'DISCOVER_PROPERTIES');
            tip_no := 2;
	 }
       else if (nfo = 'DISCOVER_PROPERTIES')
	 {
	   declare _row any;
	   _row := xpath_eval ('//root/row', xml_tree_doc (resp[0]), 0);
	   prop := make_array (length(_row), 'any');
	   prop_value := make_array (length(_row), 'any');
	   prop_type := make_array (length(_row), 'any');
	   prop_selected := make_array (length(_row), 'any');

           i := 0; l := length (prop_value);
           while (i < l)
             {
	       aset (prop, i, xpath_eval ('/row/PropertyName/text()', xml_cut (_row[i]), 1));
	       aset (prop_value, i, cast(xpath_eval ('/row/Value/text()', xml_cut (_row[i]), 1) as varchar));
	       aset (prop_type, i, xpath_eval ('/row/PropertyAccessType/text()', xml_cut (_row[i]), 1));
               i := i + 1;
	     }
           tip_no := 3;
	 }
    }
  else if (op = 2)
    {
       declare pos int;

       pos := position ('UserName', prop_list);
       if (pos > 0)
         aset (prop_list, pos, uname);
       else
         prop_list := vector_concat (prop_list, vector ('UserName', uname));

       pos := position ('Password', prop_list);
       if (pos > 0)
         aset (prop_list, pos, pwd);
       else
         prop_list := vector_concat (prop_list, vector ('Password', pwd));

       if (direction = 'backward')
	 prop_list := vector_concat (prop_list, vector ('direction', 'backward'));
       if (_skip <> '0')
         prop_list := vector_concat (prop_list, vector ('skip', atoi (_skip)));
       if (n_row)
         prop_list := vector_concat (prop_list, vector ('n-rows', atoi (n_row)));
       if (bookmark = 'on')
         prop_list := vector_concat (prop_list, vector ('return-bookmark', 1));
       if (use_bookmark = 'on')
	 {
	    declare sel_book any;
	    sel_book := get_keyword ('sel_book' , params, '');
            prop_list := vector_concat (prop_list, vector ('bookmark-from', sel_book));
	 }
       if (use_rowcount = 'on')
	 {
            prop_list := vector_concat (prop_list, vector ('retrieve-row-count', '1'));
	 }

       resp := soap_client (url=>url,
		 operation=>'Execute',
		 target_namespace=>'urn:schemas-microsoft-com:xml-analysis',
		 soap_action=>'urn:schemas-microsoft-com:xml-analysis:Execute',
		 parameters=>
		    vector ('Command', soap_box_structure ('Statement' , stmt),
			    'Properties',
			        soap_box_structure ('PropertyList',
				  prop_list
				  )),
		    --headers=>vector ('Session', xml_tree_doc (
		    --	  '<XA:EndSession'
		    --	  ||' xmlns:XA="urn:schemas-microsoft-com:xml-analysis"'
		    -- 	  ||' mustUnderstand="1" SessionID="dbf4c1b3979f4d37ca9a2bb1809e3430"/>'
		    --		 )),
		    style=>2);

       bookmarks := xpath_eval ('//BOOKMARK', xml_tree_doc (resp[0]), 0);

    }

    if (tip_no = 0)
      tip := 'Invoke the Discover method, to get the DSN info';
    else if (tip_no = 1)
      tip := 'Choose DISCOVER_SCHEMA_ROWSETS and invoke the Discover method';
    else if (tip_no = 2)
      tip := 'Choose DISCOVER_PROPERTIES and invoke the Discover method';
    else if (tip_no = 3)
      tip := 'Now you can set a property, restriction or invoke the Execute method';

  }

err:;


?>
<html>
 <HEAD>
 <link rel="stylesheet" type="text/css" href="../demo.css" />
  <STYLE>
  .filelist {
    font-family: Tahoma, sans-serif;
    background-color: #eeeeee;
    color: Black;
    border: 1px #dddddd solid;
  }
  </STYLE>
  </HEAD>
 <body>
  <H4>XML for Analysis client</H4>
  <p><?=err?></p>
  <p><?=tip?></p>
  <form method=post action="<?=http_path()?>">
  <input type="hidden" name="schema_rowsets" value="<?= encode_base64(serialize(schema_rowsets)) ?>" />

  <input type="hidden" name="propt" value="<?= encode_base64(serialize(prop)) ?>" />
  <input type="hidden" name="prop_type" value="<?= encode_base64(serialize(prop_type)) ?>" />
  <input type="hidden" name="prop_value" value="<?= encode_base64(serialize(prop_value)) ?>" />
  <input type="hidden" name="prop_selected" value="<?= encode_base64(serialize(prop_selected)) ?>" />

  <input type="hidden" name="restt" value="<?= encode_base64(serialize(rest)) ?>" />
  <input type="hidden" name="rest_type" value="<?= encode_base64(serialize(rest_type)) ?>" />
  <input type="hidden" name="rest_value" value="<?= encode_base64(serialize(rest_value)) ?>" />
  <input type="hidden" name="rest_selected" value="<?= encode_base64(serialize(rest_selected)) ?>" />

  <input type="hidden" name="tip_no" value="<?= tip_no ?>" />
  <table class="tableentry">
  <tr>
    <td>Enter a XMLA Endpoint's URL</td>
    <td><input type="text" name="url" value="<?=url?>" size="70%" /></td>
  </tr>
  <tr>
    <td>Choose Method to invoke</td>
    <td>
      <select name="op" onChange="javascript: document.forms[0].submit();">
        <option value="1" <?= case {?'op'} when '1' then 'selected' else '' end ?>>Discover</option>
        <option value="2" <?= case {?'op'} when '2' then 'selected' else '' end ?>>Execute</option>
      </select>
    </td>
  </tr>
  <tr>
    <td>DSN</td>
          <TD>
	  <select name="dsn">
	    <option><?= xmla_service_name () ?></option>
<?vsp
	    for (select ds_dsn from sys_data_source) do
	      {
?>
	        <option <?= select_if (dsn, ds_dsn) ?>><?= ds_dsn ?></option>
<?vsp
              }
?>
	  </select>
	<input type="submit" name="add_dsn" value="Add new DSN">
</td>
  </tr>
  <?vsp if (length (cast(dsn as varchar))) { ?>
   <tr>
    <td>User Name</td>
    <td><input type="text" name="uname" value="<?=uname?>" size="30%" />
    </td>
    </tr>
    <tr>
    <td>Password</td>
    <td><input type="password" name="pwd" value="<?=pwd?>" size="30%" />
    </td>
  </tr>
  <?vsp
     }
   if (length (prop) > 0) { ?>
  <tr>
    <td>Properties</td>
    <td>
	<select name="prop" onChange="javascript: document.forms[0].prop_set.value='change'; document.forms[0].submit();">
	  <?vsp
            i1 := 0; i:= 0;
	    {
             l := length (prop); i := 0;
	     while (i < l)
	       {
                 sel := '';
                 if ({?'prop'} = cast (prop[i] as varchar))
		   { sel := 'SELECTED'; i1 := i; }
	  ?>
		<option <?=sel?>><?=prop[i]?></option>
	  <?vsp
	         i := i + 1;
	       }
	     if (i > 0)
	       {
	  ?>
	</select>
	<?=prop_type[i1]?>
	<?vsp
	          if (prop_type[i1] = 'Read')
	            http (prop_value[i1]);
	          else if (prop_value[i1] is not null)
		    http (sprintf ('<input type="text" name="propv" value="%s">', prop_value[i1]));
		  else
		    http ('<input type="text" name="propv" value="">');

	          http (sprintf ('<input type="checkbox" name="props" %s>', case when prop_selected[i1] = 'on' then 'CHECKED' else '' end));
		  http ('<input type="submit" name="prop_set" value="Set" />');
                  http (sprintf ('<input type="hidden" name="prop_inx" value="%d" />', i1));
	       }
	    }
	  ?>
    </td>
  </tr>
  <?vsp  } ?>
  <?vsp if (length (rest) > 0) { ?>
  <tr>
    <td>Restrictions</td>
    <td>
	<select name="rest" onChange="javascript: document.forms[0].rest_set.value='change'; document.forms[0].submit();">
	  <?vsp
            i1 := 0; i:= 0;
	    {
             l := length (rest); i := 0;
	     while (i < l)
	       {
                 sel := '';
                 if ({?'rest'} = cast (rest[i] as varchar))
		   { sel := 'SELECTED'; i1 := i; }
	  ?>
		<option <?=sel?>><?=rest[i]?></option>
	  <?vsp
	         i := i + 1;
	       }
	     if (i > 0)
	       {
	  ?>
	</select>
	<?=rest_type[i1]?>
	<?vsp
	          if (rest_type[i1] = 'Read')
	            http (rest_value[i1]);
	          else if (rest_value[i1] is not null)
		    http (sprintf ('<input type="text" name="restv" value="%s">', rest_value[i1]));
		  else
		    http ('<input type="text" name="restv" value="">');

	          http (sprintf ('<input type="checkbox" name="rests" %s>', case when rest_selected[i1] = 'on' then 'CHECKED' else '' end));
		  http ('<input type="submit" name="rest_set" value="Set" />');
                  http (sprintf ('<input type="hidden" name="rest_inx" value="%d" />', i1));
	       }
	    }
	  ?>
    </td>
  </tr>
  <?vsp  } ?>
  <tr>
    <?vsp if (op is null or op = 1 or op ='1') { ?>
    <td>Discovery type</td>
    <td>
	<select name="nfo">
	  <?vsp
	    {
             l := length (schema_rowsets); i := 0;
	     while (i < l)
	       {
                 sel := '';
		 if (nfo = cast (schema_rowsets[i] as varchar))
	           sel := 'SELECTED';

	  ?>
		<option <?=sel?>><?=schema_rowsets[i]?></option>
	  <?vsp
	         i := i + 1;
	       }
	    }
	  ?>
	</select>
    </td>
    <?vsp } else { ?>
    </tr>
    <tr>
    <td>Statement</td>
    <td>
	<TEXTAREA name="stmt" rows=5 cols=55>
	   <?=stmt?>
	</TEXTAREA>
    </td>
    <tr>
    </tr>
    <td colspan="2">Virtuoso's Scrollable Cursor Extensions</td>
    </td>
    </tr>
    <tr>
    <td>Skip rows</td>
    <td><input type="text" name="skip" value="<?=_skip?>" size="10%" />
    </td>
    </tr>
    <tr>
    <td>N rows</td>
    <td><input type="text" name="n_row" value="<?=n_row?>" size="10%" />
    </td>
    </tr>
    <tr>
    <td>Return bookmark</td>
    <td><input type="checkbox" name="bookmark" <?= check_if (bookmark, 'on')  ?>></td>
    </td>
    </tr>
    <tr>
    <td>Direction</td>
    <td>
	  <select name="direction">
	    <option <?= select_if (direction, 'forward') ?>>forward</option>
	    <option <?= select_if (direction, 'backward') ?>>backward</option>
	  </select>
    </td>
    </tr>
<?vsp if (length (bookmarks) > 0) { ?>
    <tr>
    <td>Bookmarks</td>
    <td>
	  <select name="sel_book">
<?vsp for (idx := 0; idx < length (bookmarks); idx := idx + 1) {
	    http (sprintf ('<option>%s</option>', cast (bookmarks[idx] as varchar)));
     } ?>
	  </select>
	  <input type="checkbox" name="use_bookmark"> Use this bookmark for next exec
    </td>
  </tr>
    <tr>
    <td>
	  Use rowcount for next exec
    </td>
    <td>
	  <input type="checkbox" name="use_rowcount" <?= check_if (use_rowcount, 'on')  ?>>
    </td>
    <?vsp } ?>
    <?vsp } ?>
  </tr>
  <tr>
    <td>HTML Formatted Response</td>
    <td><input type="checkbox" name="xars" checked></td>
  </tr>
  <tr>
    <td>Start Call</td>
    <td><input type="submit" name="exec" value="Execute"></td>
  </tr>
  </table>
  </form>
<?vsp
  if (resp is not null) {
  declare inx, oux, atts any;
  inp := resp[1];
  outp := resp[2];
  --dbg_obj_print (outp);
  atts := resp[4];
  inx := xslt (TUTORIAL_XSL_DIR () || '/tutorial/services/raw.xsl', xml_tree_doc (inp), vector ('body', 0));

  if ({?'xars'} is not null)
    oux := xslt (TUTORIAL_XSL_DIR () || '/tutorial/services/xa_s_1/xars.xsl', xml_tree_doc (outp), vector ('body', 0));
  else
    oux := xslt (TUTORIAL_XSL_DIR () || '/tutorial/services/raw.xsl', xml_tree_doc (outp), vector ('body', 0));

?>
  <table>
  <tr>
    <td>
    Request
    </td>
  </tr>
  <tr>
    <td>
    <div class="filelist">
    <?vsp http_value (inx, null); ?>
    </div>
    </td>
  </tr>
  <tr>
  <tr>
    <td>
    Response
    </td>
  </tr>
    <td>
    <div class="filelist">
    <?vsp http_value (oux, null); ?>
    </div>
    </td>
  </tr>
<?vsp
      if (isarray (atts) and length (atts) > 1)
	{
          declare atta any;
          declare i, l int;
          l := length (atts); i := 1;
	  while (i < l)
	    {
	      atta := atts [i];
    ?>
       <tr>
	 <td>
	<table class="tableresult">
	  <tr> <td>Id</td> <td><?=atta[0] ?></td> </tr>
	  <tr> <td>Type</td> <td><?=atta[1] ?> </td> </tr>
	  <tr> <td>Content</td> <td><?=atta[2] ?> </td> </tr>
	</table>
	</td>
	</tr>
    <?vsp
	      i := i + 1;
	    }
      }
?>
  </table>
<?vsp
  }
?>
 </body>
</html>
